@tangle-network/ui 11.9.0 → 11.11.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 (155) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +14 -0
  3. package/dist/active-sessions-store-Gt1R0rFG.js +262 -0
  4. package/dist/{active-sessions-store-CeOmXgv5.d.ts → active-sessions-store-nl70ZnMC.d.ts} +40 -41
  5. package/dist/artifact-pane-BL_DFWNl.d.ts +32 -0
  6. package/dist/artifact-pane-DMXT9a8U.js +70 -0
  7. package/dist/auth-DixfCMCk.js +154 -0
  8. package/dist/auth.d.ts +2 -74
  9. package/dist/auth.js +2 -15
  10. package/dist/branding-26d5ARIr.d.ts +14 -0
  11. package/dist/button-uhNnwdsD.js +78 -0
  12. package/dist/button-yoIv77e2.d.ts +16 -0
  13. package/dist/chat-CPLL0Fd9.js +667 -0
  14. package/dist/chat.d.ts +2 -201
  15. package/dist/chat.js +2 -30
  16. package/dist/code-block-B9miUPht.d.ts +23 -0
  17. package/dist/code-block-CngSn37j.js +165 -0
  18. package/dist/diff-preview-cySuqowW.js +533 -0
  19. package/dist/document-editor-pane-BcoABlhn.d.ts +131 -0
  20. package/dist/document-editor-pane-Cz6oEF1o.js +1287 -0
  21. package/dist/dropdown-menu-BpcLa5vF.js +101 -0
  22. package/dist/editor.d.ts +76 -78
  23. package/dist/editor.js +2 -33
  24. package/dist/file-format-BgXbr-Ib.js +160 -0
  25. package/dist/files-CYlOo0mE.js +743 -0
  26. package/dist/files.d.ts +2 -243
  27. package/dist/files.js +3 -40
  28. package/dist/focus-Cw02pNSr.js +56 -0
  29. package/dist/format-DfcLWqMa.js +54 -0
  30. package/dist/hooks.d.ts +30 -37
  31. package/dist/hooks.js +111 -45
  32. package/dist/index-2UntyjBb.d.ts +52 -0
  33. package/dist/index-COgqsFAQ.d.ts +42 -0
  34. package/dist/index-CPDET_s1.d.ts +549 -0
  35. package/dist/index-CUhfHT_V.d.ts +204 -0
  36. package/dist/index-Cg6gYAqh.d.ts +73 -0
  37. package/dist/index-Cq-EJzqW.d.ts +16 -0
  38. package/dist/index-DhYmSaLF.d.ts +245 -0
  39. package/dist/index-DjKxO357.d.ts +128 -0
  40. package/dist/index-b56ew9aF.d.ts +107 -0
  41. package/dist/index.d.ts +26 -43
  42. package/dist/index.js +35 -460
  43. package/dist/markdown-BprL96Gl.js +45 -0
  44. package/dist/markdown.d.ts +3 -18
  45. package/dist/markdown.js +3 -14
  46. package/dist/message-vhUI0c5G.d.ts +16 -0
  47. package/dist/nav.d.ts +6 -8
  48. package/dist/nav.js +29 -11
  49. package/dist/openui-artifact-renderer-D3E5bIAI.d.ts +114 -0
  50. package/dist/openui-artifact-renderer-DT4xbvWt.js +266 -0
  51. package/dist/openui.d.ts +2 -115
  52. package/dist/openui.js +2 -12
  53. package/dist/parts-5mhy9yJ3.d.ts +37 -0
  54. package/dist/primitives-DE-blUz-.js +1239 -0
  55. package/dist/primitives.d.ts +5 -523
  56. package/dist/primitives.js +9 -211
  57. package/dist/redaction-CGGB2ENG.js +74 -0
  58. package/dist/redaction.d.ts +2 -42
  59. package/dist/redaction.js +2 -7
  60. package/dist/run-OyWmIDqu.d.ts +41 -0
  61. package/dist/run-ZsIKPA6J.js +17 -0
  62. package/dist/run-group-D1InSdQu.js +410 -0
  63. package/dist/run.d.ts +3 -126
  64. package/dist/run.js +5 -39
  65. package/dist/sdk-hooks.d.ts +2 -285
  66. package/dist/sdk-hooks.js +3 -35
  67. package/dist/stores.d.ts +13 -14
  68. package/dist/stores.js +34 -76
  69. package/dist/table-DHyqDPbU.js +146 -0
  70. package/dist/tabs-ujuqAdtb.js +40 -0
  71. package/dist/text-shimmer-BUUo6I-g.js +64 -0
  72. package/dist/tool-call-feed-BeB1_4pX.d.ts +47 -0
  73. package/dist/tool-call-feed-C1W1N54c.js +109 -0
  74. package/dist/tool-call-step-Bi3_YJRV.js +434 -0
  75. package/dist/tool-display-BAuAVa43.js +158 -0
  76. package/dist/{tool-display-z4JcDmMQ.d.ts → tool-display-DgmL5rIU.d.ts} +16 -16
  77. package/dist/tool-previews.d.ts +2 -48
  78. package/dist/tool-previews.js +2 -22
  79. package/dist/types.d.ts +6 -19
  80. package/dist/types.js +0 -1
  81. package/dist/use-auto-scroll-C5Pjeqon.js +153 -0
  82. package/dist/use-sse-stream-BjVBDbxK.js +884 -0
  83. package/dist/use-sse-stream-Dm6R5YWz.d.ts +282 -0
  84. package/dist/utils-Bl_CZ0Qp.js +37 -0
  85. package/dist/{chunk-RQHJBTEU.js → utils-C_uf36nf.js} +4 -6
  86. package/dist/utils.d.ts +2 -51
  87. package/dist/utils.js +6 -32
  88. package/package.json +39 -41
  89. package/src/auth/auth.tsx +5 -1
  90. package/src/chat/agent-timeline.tsx +6 -1
  91. package/src/chat/chat-container.tsx +2 -1
  92. package/src/editor/document-editor-pane.test.tsx +3 -1
  93. package/src/editor/document-editor-pane.tsx +5 -1
  94. package/src/editor/markdown-document-editor.test.tsx +9 -4
  95. package/src/files/file-artifact-pane.tsx +3 -2
  96. package/src/files/file-preview.tsx +3 -1
  97. package/src/files/file-tabs.tsx +9 -2
  98. package/src/lib/focus.ts +63 -0
  99. package/src/markdown/code-block.tsx +5 -1
  100. package/src/primitives/badge.tsx +2 -1
  101. package/src/primitives/button.tsx +2 -1
  102. package/src/primitives/card.tsx +1 -2
  103. package/src/primitives/dialog.tsx +7 -1
  104. package/src/primitives/input.tsx +15 -14
  105. package/src/primitives/segmented-control.tsx +5 -3
  106. package/src/primitives/select.tsx +3 -1
  107. package/src/primitives/switch.tsx +3 -1
  108. package/src/primitives/tabs.tsx +6 -4
  109. package/src/primitives/terminal-display.tsx +6 -8
  110. package/src/primitives/toast.tsx +5 -1
  111. package/src/tool-previews/command-preview.tsx +5 -1
  112. package/src/tool-previews/web-search-preview.tsx +2 -1
  113. package/src/utils/index.ts +7 -0
  114. package/dist/artifact-pane-DpuWcAiF.d.ts +0 -33
  115. package/dist/button-CMQuQEW_.d.ts +0 -17
  116. package/dist/chunk-34A66VBG.js +0 -214
  117. package/dist/chunk-3OI2QKFD.js +0 -0
  118. package/dist/chunk-3TI5DEHV.js +0 -299
  119. package/dist/chunk-4CLN43XT.js +0 -45
  120. package/dist/chunk-565EATZZ.js +0 -156
  121. package/dist/chunk-5Z5ZYMOJ.js +0 -0
  122. package/dist/chunk-6BGQA4BQ.js +0 -0
  123. package/dist/chunk-7YOCS6IF.js +0 -728
  124. package/dist/chunk-EOAX2ENE.js +0 -60
  125. package/dist/chunk-GYPQXTJU.js +0 -230
  126. package/dist/chunk-HFL6R6IF.js +0 -37
  127. package/dist/chunk-HGML45QH.js +0 -104
  128. package/dist/chunk-KNYSKNZX.js +0 -550
  129. package/dist/chunk-L57WRIND.js +0 -59
  130. package/dist/chunk-LDLOJKPC.js +0 -1585
  131. package/dist/chunk-LTEKI7YJ.js +0 -59
  132. package/dist/chunk-MKTSMWVD.js +0 -109
  133. package/dist/chunk-ND3ZFXQK.js +0 -179
  134. package/dist/chunk-NKDZ7GZE.js +0 -192
  135. package/dist/chunk-NWECTSOH.js +0 -589
  136. package/dist/chunk-OEX7NZE3.js +0 -321
  137. package/dist/chunk-Q56BYXQF.js +0 -61
  138. package/dist/chunk-REJESC5U.js +0 -117
  139. package/dist/chunk-RQGKSCEZ.js +0 -0
  140. package/dist/chunk-TN4FUEWY.js +0 -437
  141. package/dist/chunk-VPWY4I5O.js +0 -1048
  142. package/dist/chunk-WUQDUBJG.js +0 -168
  143. package/dist/chunk-XGKULLYE.js +0 -40
  144. package/dist/chunk-XU3HB5QL.js +0 -127
  145. package/dist/chunk-XYAIX4SU.js +0 -133
  146. package/dist/chunk-YJ6RE5WV.js +0 -875
  147. package/dist/chunk-YTO5V6QS.js +0 -19
  148. package/dist/chunk-ZKCEAIIZ.js +0 -1395
  149. package/dist/code-block-0kSpWMnf.d.ts +0 -25
  150. package/dist/document-editor-pane-EX25CEYW.js +0 -12
  151. package/dist/document-editor-pane-IAEQn_Dl.d.ts +0 -128
  152. package/dist/message-BHWbxBtT.d.ts +0 -15
  153. package/dist/parts-dj7AcUg0.d.ts +0 -36
  154. package/dist/run-PfLmDAox.d.ts +0 -41
  155. package/dist/tool-call-feed-D9iofJgW.d.ts +0 -46
@@ -1,875 +0,0 @@
1
- import {
2
- formatBytes
3
- } from "./chunk-4CLN43XT.js";
4
- import {
5
- detectFileFormat,
6
- fileExtension,
7
- getCodeLanguage,
8
- getFormatLabel,
9
- resolveFilePreviewKind
10
- } from "./chunk-XU3HB5QL.js";
11
- import {
12
- Button
13
- } from "./chunk-MKTSMWVD.js";
14
- import {
15
- ArtifactPane
16
- } from "./chunk-LTEKI7YJ.js";
17
- import {
18
- Markdown
19
- } from "./chunk-EOAX2ENE.js";
20
- import {
21
- CodeBlock,
22
- CopyButton
23
- } from "./chunk-WUQDUBJG.js";
24
- import {
25
- cn
26
- } from "./chunk-RQHJBTEU.js";
27
-
28
- // src/files/file-tree.tsx
29
- import { useState } from "react";
30
- import {
31
- File,
32
- FileText,
33
- FileCode,
34
- FileSpreadsheet,
35
- FileImage,
36
- Folder,
37
- FolderOpen,
38
- ChevronRight,
39
- FileJson
40
- } from "lucide-react";
41
- import { jsx, jsxs } from "react/jsx-runtime";
42
- function isNodeVisible(node, visibility) {
43
- if (!visibility) return true;
44
- if (visibility.hiddenPaths?.includes(node.path)) {
45
- return false;
46
- }
47
- if (visibility.hiddenPathPrefixes?.some(
48
- (prefix) => node.path === prefix || node.path.startsWith(`${prefix}/`)
49
- )) {
50
- return false;
51
- }
52
- return visibility.isVisible ? visibility.isVisible(node) : true;
53
- }
54
- function filterFileTree(root, visibility) {
55
- if (!isNodeVisible(root, visibility)) {
56
- return null;
57
- }
58
- if (root.type === "file") {
59
- return root;
60
- }
61
- const children = (root.children ?? []).map((child) => filterFileTree(child, visibility)).filter((child) => child !== null);
62
- if (root.children && root.children.length > 0 && children.length === 0) {
63
- return null;
64
- }
65
- return {
66
- ...root,
67
- children
68
- };
69
- }
70
- var FILE_ICONS = {
71
- pdf: FileText,
72
- csv: FileSpreadsheet,
73
- xlsx: FileSpreadsheet,
74
- xls: FileSpreadsheet,
75
- py: FileCode,
76
- ts: FileCode,
77
- js: FileCode,
78
- json: FileJson,
79
- yaml: FileCode,
80
- yml: FileCode,
81
- md: FileText,
82
- txt: FileText,
83
- png: FileImage,
84
- jpg: FileImage,
85
- jpeg: FileImage,
86
- gif: FileImage,
87
- svg: FileImage
88
- };
89
- function getFileIcon(name) {
90
- const ext = name.split(".").pop()?.toLowerCase() || "";
91
- return FILE_ICONS[ext] || File;
92
- }
93
- function getFileColor(name) {
94
- const ext = name.split(".").pop()?.toLowerCase() || "";
95
- switch (ext) {
96
- case "pdf":
97
- return "text-red-400";
98
- case "py":
99
- return "text-yellow-400";
100
- case "ts":
101
- case "js":
102
- return "text-blue-400";
103
- case "json":
104
- return "text-green-400";
105
- case "yaml":
106
- case "yml":
107
- return "text-[var(--accent-text)]";
108
- case "csv":
109
- case "xlsx":
110
- return "text-emerald-400";
111
- case "md":
112
- return "text-foreground";
113
- default:
114
- return "text-muted-foreground";
115
- }
116
- }
117
- function TreeNode({ node, depth, selectedPath, onSelect, defaultExpanded }) {
118
- const [expanded, setExpanded] = useState(defaultExpanded);
119
- const isSelected = node.path === selectedPath;
120
- const isDir = node.type === "directory";
121
- const handleClick = () => {
122
- if (isDir) {
123
- setExpanded(!expanded);
124
- }
125
- onSelect?.(node.path, node);
126
- };
127
- const Icon = isDir ? expanded ? FolderOpen : Folder : getFileIcon(node.name);
128
- const iconColor = isDir ? "text-primary" : getFileColor(node.name);
129
- return /* @__PURE__ */ jsxs("div", { children: [
130
- /* @__PURE__ */ jsxs(
131
- "button",
132
- {
133
- type: "button",
134
- className: cn(
135
- "flex items-center gap-1.5 w-full text-left px-2 py-[2px] cursor-pointer text-[13px] transition-colors",
136
- "appearance-none bg-transparent border-none",
137
- "hover:bg-accent",
138
- isSelected ? "bg-primary/15 text-foreground" : "text-foreground"
139
- ),
140
- style: { paddingLeft: `${depth * 16 + 8}px` },
141
- onClick: handleClick,
142
- "aria-expanded": isDir ? expanded : void 0,
143
- children: [
144
- isDir && /* @__PURE__ */ jsx(
145
- ChevronRight,
146
- {
147
- className: cn(
148
- "h-3 w-3 shrink-0 text-muted-foreground transition-transform",
149
- expanded && "rotate-90"
150
- )
151
- }
152
- ),
153
- !isDir && /* @__PURE__ */ jsx("span", { className: "w-3" }),
154
- /* @__PURE__ */ jsx(Icon, { className: cn("h-4 w-4 shrink-0", iconColor) }),
155
- /* @__PURE__ */ jsx("span", { className: "truncate", children: node.name }),
156
- node.size !== void 0 && !isDir && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs ml-auto tabular-nums", children: formatSize(node.size) })
157
- ]
158
- }
159
- ),
160
- isDir && expanded && node.children && /* @__PURE__ */ jsx("div", { children: node.children.sort((a, b) => {
161
- if (a.type !== b.type) return a.type === "directory" ? -1 : 1;
162
- return a.name.localeCompare(b.name);
163
- }).map((child) => /* @__PURE__ */ jsx(
164
- TreeNode,
165
- {
166
- node: child,
167
- depth: depth + 1,
168
- selectedPath,
169
- onSelect,
170
- defaultExpanded
171
- },
172
- child.path
173
- )) })
174
- ] });
175
- }
176
- function formatSize(bytes) {
177
- if (bytes < 1024) return `${bytes}B`;
178
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}K`;
179
- return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
180
- }
181
- function FileTree({
182
- root,
183
- selectedPath,
184
- onSelect,
185
- className,
186
- defaultExpanded = true,
187
- visibility
188
- }) {
189
- const visibleRoot = filterFileTree(root, visibility);
190
- if (!visibleRoot) {
191
- return null;
192
- }
193
- return /* @__PURE__ */ jsx("div", { className: cn("text-sm font-sans", className), children: visibleRoot.children ? visibleRoot.children.sort((a, b) => {
194
- if (a.type !== b.type) return a.type === "directory" ? -1 : 1;
195
- return a.name.localeCompare(b.name);
196
- }).map((child) => /* @__PURE__ */ jsx(
197
- TreeNode,
198
- {
199
- node: child,
200
- depth: 0,
201
- selectedPath,
202
- onSelect,
203
- defaultExpanded
204
- },
205
- child.path
206
- )) : /* @__PURE__ */ jsx(
207
- TreeNode,
208
- {
209
- node: visibleRoot,
210
- depth: 0,
211
- selectedPath,
212
- onSelect,
213
- defaultExpanded
214
- }
215
- ) });
216
- }
217
-
218
- // src/files/rich-file-tree.tsx
219
- import {
220
- FileTree as PierreFileTree,
221
- useFileTree as usePierreFileTree
222
- } from "@pierre/trees/react";
223
- import { useEffect, useMemo } from "react";
224
- import { jsx as jsx2 } from "react/jsx-runtime";
225
- function cssVarFromToken(name) {
226
- return `var(${name})`;
227
- }
228
- var DEFAULT_THEME = {
229
- selectedBg: cssVarFromToken("--accent-surface-soft"),
230
- selectedFg: cssVarFromToken("--accent-text"),
231
- fg: cssVarFromToken("--foreground"),
232
- hoverBg: cssVarFromToken("--muted"),
233
- border: cssVarFromToken("--border"),
234
- mutedFg: cssVarFromToken("--muted-foreground")
235
- };
236
- function flattenFileNode(node, out = []) {
237
- if (node.type === "file" && node.path) {
238
- out.push(node.path);
239
- return out;
240
- }
241
- if (node.type === "directory") {
242
- if (node.children?.length) {
243
- for (const child of node.children) {
244
- flattenFileNode(child, out);
245
- }
246
- return out;
247
- }
248
- if (node.path) out.push(`${node.path}/`);
249
- }
250
- return out;
251
- }
252
- function RichFileTree({
253
- root,
254
- paths,
255
- selectedPath,
256
- onSelect,
257
- search = true,
258
- initialExpansion = "open",
259
- gitStatus,
260
- renderContextMenu,
261
- header,
262
- themeOverrides,
263
- className,
264
- style,
265
- height
266
- }) {
267
- if (root && paths) {
268
- throw new Error("RichFileTree: pass `root` or `paths`, not both");
269
- }
270
- const flatPaths = useMemo(() => {
271
- if (paths) return Array.from(paths);
272
- if (root) return flattenFileNode(root);
273
- return [];
274
- }, [paths, root]);
275
- const { model } = usePierreFileTree({
276
- paths: flatPaths,
277
- search,
278
- initialExpansion,
279
- onSelectionChange: (selected) => {
280
- const next = selected[0];
281
- if (next && next !== selectedPath) onSelect?.(next);
282
- }
283
- });
284
- useEffect(() => {
285
- if (!gitStatus) return;
286
- model.setGitStatus(gitStatus);
287
- }, [model, gitStatus]);
288
- useEffect(() => {
289
- model.resetPaths(flatPaths);
290
- }, [model, flatPaths]);
291
- useEffect(() => {
292
- if (!selectedPath) return;
293
- const current = model.getSelectedPaths();
294
- if (current.length === 1 && current[0] === selectedPath) return;
295
- const m = model;
296
- m.setSelectedPaths?.([selectedPath]);
297
- }, [model, selectedPath]);
298
- const theme = { ...DEFAULT_THEME, ...themeOverrides };
299
- const themeStyle = useMemo(
300
- () => ({
301
- ["--trees-selected-bg-override"]: theme.selectedBg,
302
- ["--trees-selected-fg-override"]: theme.selectedFg,
303
- ["--trees-fg-override"]: theme.fg,
304
- ["--trees-hover-bg-override"]: theme.hoverBg,
305
- ["--trees-border-color-override"]: theme.border,
306
- ["--trees-muted-fg-override"]: theme.mutedFg,
307
- height: height ?? "100%",
308
- ...style
309
- }),
310
- [theme, height, style]
311
- );
312
- return /* @__PURE__ */ jsx2(
313
- PierreFileTree,
314
- {
315
- model,
316
- header,
317
- renderContextMenu,
318
- className,
319
- style: themeStyle
320
- }
321
- );
322
- }
323
-
324
- // src/files/file-preview.tsx
325
- import { useState as useState2 } from "react";
326
- import {
327
- Download,
328
- FileSpreadsheet as FileSpreadsheet2,
329
- FileText as FileText2,
330
- Music,
331
- X
332
- } from "lucide-react";
333
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
334
- var CSV_PREVIEW_ROW_LIMIT = 500;
335
- var NEEDS_DOWNLOAD_LINK = "This file needs a download link to preview.";
336
- var NO_INLINE_PREVIEW = "This file type has no inline preview.";
337
- var NO_INLINE_CONTENT = "This file has no inline content to preview yet.";
338
- function CodePreview({
339
- content,
340
- filename,
341
- kind
342
- }) {
343
- const lineCount = content.split("\n").length;
344
- const language = getCodeLanguage(filename, kind);
345
- const labelToken = fileExtension(filename) || language || "txt";
346
- return /* @__PURE__ */ jsx3(
347
- CodeBlock,
348
- {
349
- code: content,
350
- language,
351
- label: `${labelToken} \xB7 ${lineCount} lines`,
352
- showLineNumbers: true,
353
- className: "max-h-[70vh] overflow-auto",
354
- children: /* @__PURE__ */ jsx3(CopyButton, { text: content })
355
- }
356
- );
357
- }
358
- function parseCsv(content) {
359
- const rows = [];
360
- let row = [];
361
- let cell = "";
362
- let quoted = false;
363
- let inQuotes = false;
364
- const endCell = () => {
365
- row.push(quoted ? cell : cell.trim());
366
- cell = "";
367
- quoted = false;
368
- };
369
- const endRow = () => {
370
- endCell();
371
- if (row.length > 1 || row[0] !== "") rows.push(row);
372
- row = [];
373
- };
374
- for (let index = 0; index < content.length; index += 1) {
375
- const char = content[index];
376
- if (inQuotes) {
377
- if (char === '"') {
378
- if (content[index + 1] === '"') {
379
- cell += '"';
380
- index += 1;
381
- } else {
382
- inQuotes = false;
383
- }
384
- } else {
385
- cell += char;
386
- }
387
- continue;
388
- }
389
- if (char === '"') {
390
- inQuotes = true;
391
- quoted = true;
392
- continue;
393
- }
394
- if (char === ",") {
395
- endCell();
396
- continue;
397
- }
398
- if (char === "\r" || char === "\n") {
399
- if (char === "\r" && content[index + 1] === "\n") index += 1;
400
- endRow();
401
- continue;
402
- }
403
- cell += char;
404
- }
405
- if (cell.length > 0 || quoted || row.length > 0) endRow();
406
- return rows;
407
- }
408
- function CsvPreview({ content }) {
409
- const [headers = [], ...body] = parseCsv(content);
410
- if (headers.length === 0) return null;
411
- const visible = body.slice(0, CSV_PREVIEW_ROW_LIMIT);
412
- const columnCount = Math.max(headers.length, ...visible.map((cells) => cells.length));
413
- const capped = body.length > visible.length;
414
- return /* @__PURE__ */ jsxs2("div", { className: "flex min-h-0 flex-1 flex-col gap-2", children: [
415
- /* @__PURE__ */ jsx3("div", { className: "min-h-0 overflow-auto rounded-[var(--radius-md)] border border-border", children: /* @__PURE__ */ jsxs2("table", { className: "w-full text-sm", children: [
416
- /* @__PURE__ */ jsx3("thead", { children: /* @__PURE__ */ jsx3("tr", { children: Array.from({ length: columnCount }, (_, column) => /* @__PURE__ */ jsx3(
417
- "th",
418
- {
419
- className: "sticky top-0 whitespace-nowrap border-b border-border bg-card px-3 py-2 text-left text-xs font-semibold text-foreground",
420
- children: headers[column] ?? ""
421
- },
422
- column
423
- )) }) }),
424
- /* @__PURE__ */ jsx3("tbody", { children: visible.map((cells, rowIndex) => /* @__PURE__ */ jsx3("tr", { className: "border-b border-border hover:bg-accent", children: Array.from({ length: columnCount }, (_, column) => /* @__PURE__ */ jsx3(
425
- "td",
426
- {
427
- className: "whitespace-nowrap px-3 py-1.5 font-mono text-xs text-foreground",
428
- children: cells[column] ?? ""
429
- },
430
- column
431
- )) }, rowIndex)) })
432
- ] }) }),
433
- /* @__PURE__ */ jsxs2("p", { className: "shrink-0 text-xs text-muted-foreground", children: [
434
- capped ? `Showing ${visible.length} of ${body.length} rows` : `${body.length} ${body.length === 1 ? "row" : "rows"}`,
435
- ` \xB7 ${columnCount} ${columnCount === 1 ? "column" : "columns"}`
436
- ] })
437
- ] });
438
- }
439
- var CHECKER_STYLE = {
440
- backgroundColor: "var(--color-background)",
441
- backgroundImage: "repeating-conic-gradient(var(--color-muted) 0% 25%, transparent 0% 50%)",
442
- backgroundSize: "16px 16px"
443
- };
444
- function ImagePreview({ src, filename }) {
445
- const [naturalSize, setNaturalSize] = useState2(false);
446
- return /* @__PURE__ */ jsx3(
447
- "div",
448
- {
449
- className: "flex min-h-[12rem] flex-1 overflow-auto rounded-[var(--radius-md)] border border-border",
450
- style: CHECKER_STYLE,
451
- children: /* @__PURE__ */ jsx3(
452
- "button",
453
- {
454
- type: "button",
455
- onClick: () => setNaturalSize((value) => !value),
456
- "aria-pressed": naturalSize,
457
- "aria-label": naturalSize ? "Fit image to pane" : "Show image at natural size",
458
- className: cn(
459
- "flex items-center justify-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary/60",
460
- naturalSize ? "m-auto cursor-zoom-out" : "h-full w-full cursor-zoom-in p-4"
461
- ),
462
- children: /* @__PURE__ */ jsx3(
463
- "img",
464
- {
465
- src,
466
- alt: filename,
467
- draggable: false,
468
- className: naturalSize ? "max-w-none" : "max-h-full max-w-full object-contain"
469
- }
470
- )
471
- }
472
- )
473
- }
474
- );
475
- }
476
- function PdfPreview({
477
- blobUrl,
478
- filename,
479
- size,
480
- onDownload
481
- }) {
482
- return /* @__PURE__ */ jsx3(
483
- "object",
484
- {
485
- data: blobUrl,
486
- type: "application/pdf",
487
- title: filename,
488
- className: "min-h-[24rem] w-full flex-1 rounded-[var(--radius-md)]",
489
- children: /* @__PURE__ */ jsx3(
490
- DownloadCard,
491
- {
492
- filename,
493
- size,
494
- sentence: "This browser does not show PDFs inline.",
495
- onDownload,
496
- className: "h-full"
497
- }
498
- )
499
- }
500
- );
501
- }
502
- function VideoPreview({ src, filename }) {
503
- return /* @__PURE__ */ jsx3("div", { className: "flex min-h-[12rem] flex-1 items-center justify-center overflow-hidden rounded-[var(--radius-md)] border border-border bg-background", children: /* @__PURE__ */ jsx3(
504
- "video",
505
- {
506
- controls: true,
507
- preload: "metadata",
508
- src,
509
- "aria-label": filename,
510
- className: "max-h-full max-w-full"
511
- }
512
- ) });
513
- }
514
- function AudioPreview({ src, filename }) {
515
- return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4 rounded-[var(--radius-md)] border border-border bg-background px-6 py-10", children: [
516
- /* @__PURE__ */ jsx3(Music, { className: "h-10 w-10 text-muted-foreground opacity-60" }),
517
- /* @__PURE__ */ jsx3("p", { className: "max-w-full truncate text-sm font-medium text-foreground", children: filename }),
518
- /* @__PURE__ */ jsx3("audio", { controls: true, preload: "metadata", src, "aria-label": filename, className: "w-full max-w-md" })
519
- ] });
520
- }
521
- function TextPreview({ content }) {
522
- return /* @__PURE__ */ jsx3("pre", { 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]", children: content });
523
- }
524
- function MarkdownPreview({ content }) {
525
- return /* @__PURE__ */ jsx3("div", { className: "rounded-[var(--radius-md)] border border-border bg-background p-5", children: /* @__PURE__ */ jsx3(Markdown, { children: content }) });
526
- }
527
- function DownloadCard({
528
- filename,
529
- size,
530
- sentence,
531
- icon: Icon = FileText2,
532
- onDownload,
533
- className
534
- }) {
535
- return /* @__PURE__ */ jsxs2(
536
- "div",
537
- {
538
- className: cn(
539
- "flex flex-col items-center justify-center rounded-[var(--radius-md)] border border-dashed border-border bg-background px-6 py-16 text-center",
540
- className
541
- ),
542
- children: [
543
- /* @__PURE__ */ jsx3(Icon, { className: "mb-3 h-12 w-12 text-muted-foreground opacity-40" }),
544
- /* @__PURE__ */ jsx3("p", { className: "max-w-full truncate text-sm font-medium text-foreground", children: filename }),
545
- size !== void 0 && /* @__PURE__ */ jsx3("p", { className: "mt-1 text-xs text-muted-foreground", children: formatBytes(size) }),
546
- /* @__PURE__ */ jsx3("p", { className: "mt-3 max-w-md text-sm text-muted-foreground", children: sentence }),
547
- onDownload && /* @__PURE__ */ jsxs2(Button, { type: "button", variant: "outline", size: "sm", className: "mt-5", onClick: onDownload, children: [
548
- /* @__PURE__ */ jsx3(Download, {}),
549
- "Download"
550
- ] })
551
- ]
552
- }
553
- );
554
- }
555
- function PreviewBody({
556
- kind,
557
- filename,
558
- content,
559
- blobUrl,
560
- size,
561
- onDownload
562
- }) {
563
- const hasText = typeof content === "string";
564
- const card = (sentence, icon) => /* @__PURE__ */ jsx3(
565
- DownloadCard,
566
- {
567
- filename,
568
- size,
569
- sentence,
570
- icon,
571
- onDownload
572
- }
573
- );
574
- switch (kind) {
575
- case "pdf":
576
- if (blobUrl) {
577
- return /* @__PURE__ */ jsx3(PdfPreview, { blobUrl, filename, size, onDownload });
578
- }
579
- return card(NEEDS_DOWNLOAD_LINK);
580
- case "image":
581
- if (blobUrl) return /* @__PURE__ */ jsx3(ImagePreview, { src: blobUrl, filename });
582
- if (hasText) return /* @__PURE__ */ jsx3(CodePreview, { content, filename, kind: "code" });
583
- return card(NEEDS_DOWNLOAD_LINK);
584
- case "video":
585
- if (blobUrl) return /* @__PURE__ */ jsx3(VideoPreview, { src: blobUrl, filename });
586
- return card(NEEDS_DOWNLOAD_LINK);
587
- case "audio":
588
- if (blobUrl) return /* @__PURE__ */ jsx3(AudioPreview, { src: blobUrl, filename });
589
- return card(NEEDS_DOWNLOAD_LINK, Music);
590
- case "csv":
591
- if (hasText) return /* @__PURE__ */ jsx3(CsvPreview, { content });
592
- return card(NO_INLINE_CONTENT, FileSpreadsheet2);
593
- case "code":
594
- case "json":
595
- case "yaml":
596
- if (hasText) return /* @__PURE__ */ jsx3(CodePreview, { content, filename, kind });
597
- return card(NO_INLINE_CONTENT);
598
- case "markdown":
599
- if (hasText) return /* @__PURE__ */ jsx3(MarkdownPreview, { content });
600
- return card(NO_INLINE_CONTENT);
601
- case "text":
602
- if (hasText) return /* @__PURE__ */ jsx3(TextPreview, { content });
603
- return card(NO_INLINE_CONTENT);
604
- case "spreadsheet":
605
- return card("Download to open this workbook in a spreadsheet app.", FileSpreadsheet2);
606
- case "binary":
607
- if (hasText) return /* @__PURE__ */ jsx3(TextPreview, { content });
608
- return card(blobUrl ? NO_INLINE_PREVIEW : NEEDS_DOWNLOAD_LINK);
609
- }
610
- }
611
- function FilePreview({
612
- filename,
613
- content,
614
- blobUrl,
615
- mimeType,
616
- size,
617
- onClose,
618
- onDownload,
619
- hideHeader = false,
620
- className
621
- }) {
622
- const kind = resolveFilePreviewKind(filename, mimeType);
623
- const previewLabel = getFormatLabel(kind);
624
- return /* @__PURE__ */ jsxs2("div", { className: cn("flex flex-col h-full", className), children: [
625
- !hideHeader && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border shrink-0", children: [
626
- /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
627
- /* @__PURE__ */ jsx3("div", { className: "truncate text-sm font-medium text-foreground", children: filename }),
628
- /* @__PURE__ */ jsx3("div", { className: "mt-0.5 text-[11px] uppercase tracking-[0.12em] text-muted-foreground", children: previewLabel })
629
- ] }),
630
- onDownload && /* @__PURE__ */ jsx3(
631
- "button",
632
- {
633
- type: "button",
634
- onClick: onDownload,
635
- "aria-label": `Download ${filename}`,
636
- className: "p-1.5 rounded-[var(--radius-sm)] hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
637
- children: /* @__PURE__ */ jsx3(Download, { className: "h-4 w-4" })
638
- }
639
- ),
640
- onClose && /* @__PURE__ */ jsx3(
641
- "button",
642
- {
643
- type: "button",
644
- onClick: onClose,
645
- "aria-label": `Close ${filename}`,
646
- className: "p-1.5 rounded-[var(--radius-sm)] hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
647
- children: /* @__PURE__ */ jsx3(X, { className: "h-4 w-4" })
648
- }
649
- )
650
- ] }),
651
- /* @__PURE__ */ jsx3("div", { className: "flex min-h-0 flex-1 flex-col overflow-auto p-3", children: /* @__PURE__ */ jsx3(
652
- PreviewBody,
653
- {
654
- kind,
655
- filename,
656
- content,
657
- blobUrl,
658
- size,
659
- onDownload
660
- }
661
- ) })
662
- ] });
663
- }
664
-
665
- // src/files/file-tabs.tsx
666
- import { X as X2, FileText as FileText3, FileCode as FileCode2, FileSpreadsheet as FileSpreadsheet3 } from "lucide-react";
667
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
668
- function getTabIcon(name) {
669
- const ext = name.split(".").pop()?.toLowerCase() || "";
670
- if (["pdf"].includes(ext)) return FileText3;
671
- if (["csv", "xlsx"].includes(ext)) return FileSpreadsheet3;
672
- return FileCode2;
673
- }
674
- function FileTabs({ tabs, activeId, onSelect, onClose, className }) {
675
- if (tabs.length === 0) return null;
676
- return /* @__PURE__ */ jsx4("div", { className: cn("flex items-center border-b border-border bg-background overflow-x-auto", className), children: tabs.map((tab) => {
677
- const isActive = tab.id === activeId;
678
- const Icon = getTabIcon(tab.name);
679
- return /* @__PURE__ */ jsxs3(
680
- "div",
681
- {
682
- className: cn(
683
- "group flex items-center border-r border-border shrink-0",
684
- isActive ? "bg-card text-foreground border-b-2 border-b-primary" : "text-muted-foreground hover:bg-muted/50"
685
- ),
686
- children: [
687
- /* @__PURE__ */ jsxs3(
688
- "button",
689
- {
690
- type: "button",
691
- onClick: () => onSelect(tab.id),
692
- className: "flex min-w-0 items-center gap-1.5 px-3 py-1.5 text-xs transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary/60",
693
- children: [
694
- /* @__PURE__ */ jsx4(Icon, { className: "h-3 w-3 shrink-0" }),
695
- /* @__PURE__ */ jsx4("span", { className: "max-w-[120px] truncate", children: tab.name }),
696
- tab.dirty && /* @__PURE__ */ jsx4("span", { className: "h-1.5 w-1.5 rounded-full bg-primary" })
697
- ]
698
- }
699
- ),
700
- /* @__PURE__ */ jsx4(
701
- "button",
702
- {
703
- type: "button",
704
- "aria-label": `Close ${tab.name}`,
705
- onClick: () => onClose(tab.id),
706
- className: "mr-1 rounded p-0.5 opacity-0 transition-opacity hover:bg-accent focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 group-hover:opacity-100",
707
- children: /* @__PURE__ */ jsx4(X2, { className: "h-2.5 w-2.5" })
708
- }
709
- )
710
- ]
711
- },
712
- tab.id
713
- );
714
- }) });
715
- }
716
-
717
- // src/files/file-artifact-pane.tsx
718
- import { lazy, Suspense } from "react";
719
- import { Download as Download2, X as X3 } from "lucide-react";
720
- import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
721
- var LazyDocumentEditorPane = lazy(async () => {
722
- const module = await import("./document-editor-pane-EX25CEYW.js");
723
- return { default: module.DocumentEditorPane };
724
- });
725
- function FileArtifactPane({
726
- filename,
727
- content,
728
- blobUrl,
729
- mimeType,
730
- size,
731
- onClose,
732
- onDownload,
733
- path,
734
- tabs = [],
735
- activeTabId,
736
- onTabSelect,
737
- onTabClose,
738
- eyebrow = "Artifact",
739
- meta,
740
- toolbar,
741
- footer,
742
- className,
743
- headerClassName,
744
- hideTitleBlock,
745
- editor
746
- }) {
747
- const showTabs = tabs.length > 0 && onTabSelect && onTabClose;
748
- const paneTabs = showTabs ? /* @__PURE__ */ jsx5(
749
- FileTabs,
750
- {
751
- tabs,
752
- activeId: activeTabId,
753
- onSelect: onTabSelect,
754
- onClose: onTabClose
755
- }
756
- ) : void 0;
757
- const isMarkdown = detectFileFormat(filename, mimeType) === "markdown" || (path ? detectFileFormat(path, mimeType) === "markdown" : false);
758
- const isEditableMarkdown = isMarkdown && editor?.enabled;
759
- const headerActions = onDownload || onClose ? /* @__PURE__ */ jsxs4(Fragment, { children: [
760
- onDownload && /* @__PURE__ */ jsx5(
761
- "button",
762
- {
763
- type: "button",
764
- "aria-label": `Download ${filename}`,
765
- onClick: onDownload,
766
- className: "rounded-[var(--radius-sm)] p-1.5 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
767
- children: /* @__PURE__ */ jsx5(Download2, { className: "h-4 w-4" })
768
- }
769
- ),
770
- onClose && /* @__PURE__ */ jsx5(
771
- "button",
772
- {
773
- type: "button",
774
- "aria-label": `Close ${filename}`,
775
- onClick: onClose,
776
- className: "rounded-[var(--radius-sm)] p-1.5 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
777
- children: /* @__PURE__ */ jsx5(X3, { className: "h-4 w-4" })
778
- }
779
- )
780
- ] }) : void 0;
781
- if (isEditableMarkdown) {
782
- return /* @__PURE__ */ jsx5(
783
- Suspense,
784
- {
785
- fallback: /* @__PURE__ */ jsx5(
786
- ArtifactPane,
787
- {
788
- eyebrow,
789
- title: filename,
790
- subtitle: path,
791
- meta,
792
- toolbar,
793
- footer,
794
- className,
795
- tabs: paneTabs,
796
- headerActions,
797
- headerClassName,
798
- hideTitleBlock,
799
- children: /* @__PURE__ */ jsx5("div", { 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", children: "Loading editor\u2026" })
800
- }
801
- ),
802
- children: /* @__PURE__ */ jsx5(
803
- LazyDocumentEditorPane,
804
- {
805
- eyebrow,
806
- title: filename,
807
- subtitle: path,
808
- meta,
809
- toolbar,
810
- footer,
811
- className,
812
- tabs: paneTabs,
813
- headerActions,
814
- headerClassName,
815
- hideTitleBlock,
816
- markdown: content ?? "",
817
- mode: editor.mode,
818
- defaultMode: editor.defaultMode,
819
- onModeChange: editor.onModeChange,
820
- backend: editor.backend,
821
- collaboration: editor.collaboration,
822
- placeholder: editor.placeholder,
823
- autoFocus: editor.autoFocus,
824
- readOnly: editor.readOnly,
825
- saving: editor.saving,
826
- saveLabel: editor.saveLabel,
827
- onChange: editor.onChange,
828
- onSave: editor.onSave,
829
- previewClassName: editor.previewClassName,
830
- editorClassName: editor.editorClassName
831
- }
832
- )
833
- }
834
- );
835
- }
836
- return /* @__PURE__ */ jsx5(
837
- ArtifactPane,
838
- {
839
- eyebrow,
840
- title: filename,
841
- subtitle: path,
842
- meta,
843
- toolbar,
844
- footer,
845
- className,
846
- tabs: paneTabs,
847
- headerActions,
848
- headerClassName,
849
- hideTitleBlock,
850
- children: /* @__PURE__ */ jsx5(
851
- FilePreview,
852
- {
853
- filename,
854
- content,
855
- blobUrl,
856
- mimeType,
857
- size,
858
- onDownload,
859
- hideHeader: true
860
- }
861
- )
862
- }
863
- );
864
- }
865
-
866
- export {
867
- filterFileTree,
868
- FileTree,
869
- RichFileTree,
870
- CSV_PREVIEW_ROW_LIMIT,
871
- parseCsv,
872
- FilePreview,
873
- FileTabs,
874
- FileArtifactPane
875
- };