ai-design-system 0.1.53 → 0.1.54

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.
@@ -61,6 +61,10 @@ export interface AIConversationProps
61
61
  description?: string
62
62
  icon?: React.ReactNode
63
63
  }
64
+ /**
65
+ * Callback fired when a tool action (like a link click) is triggered
66
+ */
67
+ onToolAction?: (toolCall: ToolCall, action: string) => void
64
68
  }
65
69
 
66
70
  /**
@@ -73,6 +77,7 @@ export const AIConversation = React.memo<AIConversationProps>(
73
77
  onSelectSubAgent,
74
78
  selectedSubAgent,
75
79
  emptyState,
80
+ onToolAction,
76
81
  ...conversationProps
77
82
  }) => {
78
83
  const isEmpty = React.useMemo(
@@ -146,7 +151,7 @@ export const AIConversation = React.memo<AIConversationProps>(
146
151
  >
147
152
  {/* Render direct tool calls */}
148
153
  {directToolCalls.map((tc) => (
149
- <ToolCallDisplay key={tc.id} toolCall={tc} />
154
+ <ToolCallDisplay key={tc.id} toolCall={tc} onToolAction={onToolAction} />
150
155
  ))}
151
156
 
152
157
  {/* Render specialist sub-agents */}
@@ -41,6 +41,40 @@ function renderTree(nodes: FileTreeNode[]): React.ReactNode {
41
41
  })
42
42
  }
43
43
 
44
+ function filterTree(nodes: FileTreeNode[], query: string): FileTreeNode[] {
45
+ if (!query) return nodes;
46
+ const lowerQuery = query.toLowerCase();
47
+
48
+ return nodes.reduce<FileTreeNode[]>((acc, node) => {
49
+ if (node.type === 'file') {
50
+ if (node.name.toLowerCase().includes(lowerQuery)) {
51
+ acc.push(node);
52
+ }
53
+ } else if (node.type === 'folder' && node.children) {
54
+ const filteredChildren = filterTree(node.children, query);
55
+ // Keep the folder if it matches the query itself, or if any of its children match
56
+ if (node.name.toLowerCase().includes(lowerQuery) || filteredChildren.length > 0) {
57
+ acc.push({ ...node, children: filteredChildren });
58
+ }
59
+ }
60
+ return acc;
61
+ }, []);
62
+ }
63
+
64
+ function getAllFolderPaths(nodes: FileTreeNode[]): Set<string> {
65
+ const paths = new Set<string>();
66
+ function traverse(n: FileTreeNode[]) {
67
+ for (const node of n) {
68
+ if (node.type === 'folder') {
69
+ paths.add(node.path);
70
+ if (node.children) traverse(node.children);
71
+ }
72
+ }
73
+ }
74
+ traverse(nodes);
75
+ return paths;
76
+ }
77
+
44
78
  export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
45
79
  ({
46
80
  tree,
@@ -53,6 +87,19 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
53
87
  headerClassName,
54
88
  className,
55
89
  }) => {
90
+ const [searchQuery, setSearchQuery] = React.useState("")
91
+
92
+ const filteredTree = React.useMemo(() => {
93
+ return filterTree(tree, searchQuery)
94
+ }, [tree, searchQuery])
95
+
96
+ const expandedPaths = React.useMemo(() => {
97
+ if (searchQuery) {
98
+ return getAllFolderPaths(filteredTree)
99
+ }
100
+ return defaultExpanded
101
+ }, [searchQuery, filteredTree, defaultExpanded])
102
+
56
103
  return (
57
104
  <div className={cn("flex flex-col rounded-lg border bg-background", className)}>
58
105
  <div className={cn("flex items-center gap-2 border-b px-3 py-2", headerClassName)}>
@@ -64,6 +111,8 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
64
111
  />
65
112
  <Input
66
113
  placeholder={searchPlaceholder}
114
+ value={searchQuery}
115
+ onChange={(e) => setSearchQuery(e.target.value)}
67
116
  className="pl-8"
68
117
  />
69
118
  </div>
@@ -80,11 +129,12 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
80
129
  </div>
81
130
  <div className="p-2">
82
131
  <FileTree
83
- defaultExpanded={defaultExpanded}
132
+ className="border-none bg-transparent"
133
+ defaultExpanded={expandedPaths}
84
134
  selectedPath={selectedPath}
85
135
  onSelect={onSelect}
86
136
  >
87
- {renderTree(tree)}
137
+ {renderTree(filteredTree)}
88
138
  </FileTree>
89
139
  </div>
90
140
  </div>
@@ -1,4 +1,5 @@
1
1
  import * as React from "react"
2
+ import { Icon } from "@/components/primitives/Icon"
2
3
  import {
3
4
  Tool,
4
5
  ToolHeader,
@@ -20,6 +21,9 @@ export interface ToolCall {
20
21
  args: Record<string, unknown>
21
22
  result?: string
22
23
  status: "pending" | "completed" | "error"
24
+ uiVariant?: "default" | "link"
25
+ linkText?: string
26
+ linkAction?: string
23
27
  }
24
28
 
25
29
  export interface ToolCallDisplayProps {
@@ -31,13 +35,17 @@ export interface ToolCallDisplayProps {
31
35
  * Whether the tool call is initially expanded
32
36
  */
33
37
  defaultExpanded?: boolean
38
+ /**
39
+ * Callback fired when a tool action (like a link click) is triggered
40
+ */
41
+ onToolAction?: (toolCall: ToolCall, action: string) => void
34
42
  }
35
43
 
36
44
  /**
37
45
  * ToolCallDisplay component - displays tool execution with expandable details
38
46
  */
39
47
  export const ToolCallDisplay = React.memo<ToolCallDisplayProps>(
40
- ({ toolCall, defaultExpanded = false }) => {
48
+ ({ toolCall, defaultExpanded = false, onToolAction }) => {
41
49
  const [isExpanded, setIsExpanded] = React.useState(defaultExpanded)
42
50
 
43
51
  const { name, args, result, status } = React.useMemo(() => {
@@ -78,6 +86,26 @@ export const ToolCallDisplay = React.memo<ToolCallDisplayProps>(
78
86
  }
79
87
  }, [status])
80
88
 
89
+ if (toolCall.uiVariant === "link") {
90
+ return (
91
+ <div
92
+ className="flex items-center gap-2 p-3 my-2 rounded-md border bg-muted/30 cursor-pointer hover:bg-muted/50 transition-colors"
93
+ onClick={(e) => {
94
+ e.preventDefault();
95
+ e.stopPropagation();
96
+ if (toolCall.linkAction && onToolAction) {
97
+ onToolAction(toolCall, toolCall.linkAction);
98
+ }
99
+ }}
100
+ >
101
+ <Icon name="external-link" className="size-4 text-blue-500" />
102
+ <span className="font-medium text-sm text-blue-500 hover:underline">
103
+ {toolCall.linkText || `${name} Action`}
104
+ </span>
105
+ </div>
106
+ )
107
+ }
108
+
81
109
  return (
82
110
  <Tool open={isExpanded} onOpenChange={setIsExpanded}>
83
111
  <ToolHeader
@@ -103,6 +103,8 @@ export interface AIDocEditorMultiTabProps {
103
103
  onTabClose?: (documentId: string) => void
104
104
  /** Optional completely separate file tree to show all available files in the explorer (even closed ones). If not provided, it falls back to showing only the currently open documents. */
105
105
  fileTree?: FileTreeNode[]
106
+ /** When true, hides the document tab bar — useful for single-file mode where the file tree provides navigation. */
107
+ hideTabBar?: boolean
106
108
  }
107
109
 
108
110
  /**
@@ -273,60 +275,70 @@ export const AIDocEditor = React.memo<AIDocEditorProps>(
273
275
  /**
274
276
  * Multi-tab mode
275
277
  */
278
+ const { hideTabBar } = props as AIDocEditorMultiTabProps
279
+
280
+ let editorPane: React.ReactNode
281
+
276
282
  if (!currentDocument) {
277
- return (
278
- <div className={cn('ai-doc-editor flex flex-col flex-1 h-screen w-full', className)}>
279
- <DocumentTabBar
280
- tabs={props.documents?.map((doc) => doc.file) || []}
281
- activeTabId={props.activeDocumentId}
282
- onTabSelect={props.onTabSelect}
283
- onTabClose={props.onTabClose}
284
- />
283
+ editorPane = (
284
+ <div className="ai-doc-editor flex flex-col h-full w-full">
285
+ {!hideTabBar && (
286
+ <DocumentTabBar
287
+ className="w-full"
288
+ tabs={props.documents?.map((doc) => doc.file) || []}
289
+ activeTabId={props.activeDocumentId}
290
+ onTabSelect={props.onTabSelect}
291
+ onTabClose={props.onTabClose}
292
+ />
293
+ )}
285
294
  <div className="flex-1 flex items-center justify-center p-6 text-muted-foreground">
286
295
  No documents open
287
296
  </div>
288
297
  </div>
289
298
  )
290
- }
299
+ } else {
300
+ const isMarkdownMulti = currentDocument.file.format === 'markdown'
291
301
 
292
- const isMarkdownMulti = currentDocument.file.format === 'markdown'
293
-
294
- const editorPane = (
295
- <div className="ai-doc-editor flex flex-col h-full w-full">
296
- <DocumentTabBar
297
- className="w-full"
298
- tabs={props.documents?.map((doc) => doc.file) || []}
299
- activeTabId={props.activeDocumentId}
300
- onTabSelect={props.onTabSelect}
301
- onTabClose={props.onTabClose}
302
- />
303
- <div className="flex-1 overflow-auto">
304
- {isMarkdownMulti ? (
305
- <div className="p-6">
306
- <Streamdown
307
- mode="streaming"
308
- isAnimating
309
- className="[&>*:first-child]:mt-0 [&>*:last-child]:mb-0"
310
- >
311
- {currentDocument.content as string}
312
- </Streamdown>
313
- </div>
314
- ) : (
315
- <DocumentEditorWithComments
316
- content={currentDocument.content}
317
- format={currentDocument.file.format as 'json' | 'markdown' | undefined}
318
- annotations={currentDocument.annotations}
319
- currentUserId={currentUser.id}
320
- currentUserName={currentUser.name}
321
- readOnly={mode === 'readonly'}
322
- onAnnotationAdd={handleAnnotationAdd}
323
- onAnnotationUpdate={handleAnnotationUpdate}
324
- className="p-6 h-full flex flex-col"
302
+ editorPane = (
303
+ <div className="ai-doc-editor flex flex-col h-full w-full">
304
+ {!hideTabBar && (
305
+ <DocumentTabBar
306
+ className="w-full"
307
+ tabs={props.documents?.map((doc) => doc.file) || []}
308
+ activeTabId={props.activeDocumentId}
309
+ onTabSelect={props.onTabSelect}
310
+ onTabClose={props.onTabClose}
325
311
  />
326
312
  )}
313
+ <div className="flex-1 overflow-auto">
314
+ {isMarkdownMulti ? (
315
+ <div className="p-6">
316
+ <Streamdown
317
+ mode="streaming"
318
+ isAnimating
319
+ className="[&>*:first-child]:mt-0 [&>*:last-child]:mb-0"
320
+ >
321
+ {currentDocument.content as string}
322
+ </Streamdown>
323
+ </div>
324
+ ) : (
325
+ <DocumentEditorWithComments
326
+ content={currentDocument.content}
327
+ format={currentDocument.file.format as 'json' | 'markdown' | undefined}
328
+ annotations={currentDocument.annotations}
329
+ selectedAnnotationId={props.selectedAnnotationId}
330
+ currentUserId={currentUser.id}
331
+ currentUserName={currentUser.name}
332
+ readOnly={mode === 'readonly'}
333
+ onAnnotationAdd={handleAnnotationAdd}
334
+ onAnnotationUpdate={handleAnnotationUpdate}
335
+ className="ai-doc-editor p-6 min-h-full"
336
+ />
337
+ )}
338
+ </div>
327
339
  </div>
328
- </div>
329
- )
340
+ )
341
+ }
330
342
 
331
343
  return (
332
344
  <AdjustableLayout
@@ -127,17 +127,12 @@ function useMultiTabDocEditorMockState(
127
127
 
128
128
  const closeDocument = useCallback((documentId: string) => {
129
129
  console.log('[Multi-Tab Mock] Closing document:', documentId)
130
- setDocuments(prev => {
131
- const filtered = prev.filter(doc => doc.file.id !== documentId)
132
- if (activeDocumentId === documentId && filtered.length > 0) {
133
- setActiveDocumentId(filtered[0].file.id)
134
- }
135
- if (filtered.length === 0) {
136
- setActiveDocumentId(undefined)
137
- }
138
- return filtered
139
- })
140
- }, [activeDocumentId])
130
+ setDocuments(prev => prev.filter(doc => doc.file.id !== documentId))
131
+ if (activeDocumentId === documentId) {
132
+ const filtered = documents.filter(doc => doc.file.id !== documentId)
133
+ setActiveDocumentId(filtered.length > 0 ? filtered[0].file.id : undefined)
134
+ }
135
+ }, [activeDocumentId, documents])
141
136
 
142
137
  const switchDocument = useCallback((documentId: string) => {
143
138
  console.log('[Multi-Tab Mock] Switching to document:', documentId)
@@ -101,6 +101,10 @@ export interface RefinementPanelProps {
101
101
  * Additional CSS classes
102
102
  */
103
103
  className?: string;
104
+ /**
105
+ * Action handler for tool interactions
106
+ */
107
+ onToolAction?: (toolCall: ToolCall, action: string) => void;
104
108
  }
105
109
 
106
110
  /**
@@ -122,6 +126,7 @@ export const RefinementPanel = React.memo<RefinementPanelProps>(
122
126
  loading = false,
123
127
  placeholder = "Ask a question or describe a task...",
124
128
  className,
129
+ onToolAction,
125
130
  }) => {
126
131
  // File change queue state
127
132
  const [fileChangeState, setFileChangeState] = React.useState<
@@ -262,6 +267,7 @@ export const RefinementPanel = React.memo<RefinementPanelProps>(
262
267
  <AIConversation
263
268
  messages={messages}
264
269
  showAvatars={true}
270
+ onToolAction={onToolAction}
265
271
  className="flex-1 min-h-0"
266
272
  />
267
273
  <div className="sticky bottom-0 z-10 p-4 bg-gradient-to-t from-card via-card to-transparent pt-6">
@@ -11,6 +11,7 @@
11
11
  import type { RefinementMessage } from "./RefinementPanel";
12
12
  import type { FileChangeData } from "@/components/composites/FileQueue";
13
13
  import type { ActionRequest, ReviewConfig } from "@/components/composites/ApprovalCard";
14
+ import type { ToolCall } from "@/components/composites/ToolCallDisplay";
14
15
 
15
16
  /**
16
17
  * Return type for the refinement panel hook
@@ -51,6 +52,9 @@ export interface UseRefinementPanelReturn {
51
52
 
52
53
  /** Processing state for HITL approval */
53
54
  isApprovalProcessing?: boolean;
55
+
56
+ /** Action handler for tool interactions */
57
+ handleToolAction?: (toolCall: ToolCall, action: string) => void;
54
58
  }
55
59
 
56
60
  /**
@@ -3,6 +3,7 @@ import type { RefinementMessage } from "./RefinementPanel";
3
3
  import type { FileChangeData } from "@/components/composites/FileQueue";
4
4
  import type { PromptInputMessage } from "@/components/ai-elements/prompt-input";
5
5
  import type { ActionRequest, ReviewConfig } from "@/components/composites/ApprovalCard";
6
+ import type { ToolCall } from "@/components/composites/ToolCallDisplay";
6
7
  import type { FormEvent } from "react";
7
8
 
8
9
  export interface UseRefinementPanelReturn {
@@ -19,6 +20,7 @@ export interface UseRefinementPanelReturn {
19
20
  handleApprovalReject?: (reason: string) => Promise<void>;
20
21
  handleApprovalEdit?: (editedArgs: Record<string, unknown>) => Promise<void>;
21
22
  isApprovalProcessing?: boolean;
23
+ handleToolAction?: (toolCall: ToolCall, action: string) => void;
22
24
  }
23
25
 
24
26
  export interface UseRefinementPanelOptions {
@@ -173,5 +175,6 @@ export function useRefinementPanelMock(
173
175
  handleApprovalReject: initialApprovalRequest ? handleApprovalReject : undefined,
174
176
  handleApprovalEdit: initialApprovalRequest ? handleApprovalEdit : undefined,
175
177
  isApprovalProcessing,
178
+ handleToolAction: (toolCall, action) => console.log(`[Mock Tool Action] ${action} on tool:`, toolCall),
176
179
  };
177
180
  }
package/dist/index.cjs CHANGED
@@ -3242,7 +3242,7 @@ var ToolOutput = (_a) => {
3242
3242
  ] }));
3243
3243
  };
3244
3244
  var ToolCallDisplay = React3__namespace.memo(
3245
- ({ toolCall, defaultExpanded = false }) => {
3245
+ ({ toolCall, defaultExpanded = false, onToolAction }) => {
3246
3246
  const [isExpanded, setIsExpanded] = React3__namespace.useState(defaultExpanded);
3247
3247
  const { name, args, result, status } = React3__namespace.useMemo(() => {
3248
3248
  const toolName = toolCall.name || "Unknown Tool";
@@ -3277,6 +3277,25 @@ var ToolCallDisplay = React3__namespace.memo(
3277
3277
  return "output-available";
3278
3278
  }
3279
3279
  }, [status]);
3280
+ if (toolCall.uiVariant === "link") {
3281
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3282
+ "div",
3283
+ {
3284
+ className: "flex items-center gap-2 p-3 my-2 rounded-md border bg-muted/30 cursor-pointer hover:bg-muted/50 transition-colors",
3285
+ onClick: (e) => {
3286
+ e.preventDefault();
3287
+ e.stopPropagation();
3288
+ if (toolCall.linkAction && onToolAction) {
3289
+ onToolAction(toolCall, toolCall.linkAction);
3290
+ }
3291
+ },
3292
+ children: [
3293
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "external-link", className: "size-4 text-blue-500" }),
3294
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-sm text-blue-500 hover:underline", children: toolCall.linkText || `${name} Action` })
3295
+ ]
3296
+ }
3297
+ );
3298
+ }
3280
3299
  return /* @__PURE__ */ jsxRuntime.jsxs(Tool, { open: isExpanded, onOpenChange: setIsExpanded, children: [
3281
3300
  /* @__PURE__ */ jsxRuntime.jsx(
3282
3301
  ToolHeader,
@@ -3395,13 +3414,15 @@ var AIConversation = React3__namespace.memo(
3395
3414
  showAvatars = true,
3396
3415
  onSelectSubAgent,
3397
3416
  selectedSubAgent,
3398
- emptyState
3417
+ emptyState,
3418
+ onToolAction
3399
3419
  } = _b, conversationProps = __objRest(_b, [
3400
3420
  "messages",
3401
3421
  "showAvatars",
3402
3422
  "onSelectSubAgent",
3403
3423
  "selectedSubAgent",
3404
- "emptyState"
3424
+ "emptyState",
3425
+ "onToolAction"
3405
3426
  ]);
3406
3427
  const isEmpty = React3__namespace.useMemo(
3407
3428
  () => messages.length === 0,
@@ -3456,7 +3477,7 @@ var AIConversation = React3__namespace.memo(
3456
3477
  },
3457
3478
  showAvatar: showAvatars,
3458
3479
  children: [
3459
- directToolCalls.map((tc) => /* @__PURE__ */ jsxRuntime.jsx(ToolCallDisplay, { toolCall: tc }, tc.id)),
3480
+ directToolCalls.map((tc) => /* @__PURE__ */ jsxRuntime.jsx(ToolCallDisplay, { toolCall: tc, onToolAction }, tc.id)),
3460
3481
  subAgents.map((subAgent) => /* @__PURE__ */ jsxRuntime.jsx(
3461
3482
  SpecialistMessage,
3462
3483
  {
@@ -5521,7 +5542,8 @@ var RefinementPanel = React3__namespace.memo(
5521
5542
  isApprovalProcessing = false,
5522
5543
  loading = false,
5523
5544
  placeholder = "Ask a question or describe a task...",
5524
- className
5545
+ className,
5546
+ onToolAction
5525
5547
  }) => {
5526
5548
  const [fileChangeState, setFileChangeState] = React3__namespace.useState("approval-requested");
5527
5549
  const [approval, setApproval] = React3__namespace.useState({});
@@ -5632,6 +5654,7 @@ var RefinementPanel = React3__namespace.memo(
5632
5654
  {
5633
5655
  messages,
5634
5656
  showAvatars: true,
5657
+ onToolAction,
5635
5658
  className: "flex-1 min-h-0"
5636
5659
  }
5637
5660
  ),
@@ -10758,6 +10781,36 @@ function renderTree(nodes) {
10758
10781
  return /* @__PURE__ */ jsxRuntime.jsx(FileTreeFile, { name: node.name, path: node.path }, node.path);
10759
10782
  });
10760
10783
  }
10784
+ function filterTree(nodes, query) {
10785
+ if (!query) return nodes;
10786
+ const lowerQuery = query.toLowerCase();
10787
+ return nodes.reduce((acc, node) => {
10788
+ if (node.type === "file") {
10789
+ if (node.name.toLowerCase().includes(lowerQuery)) {
10790
+ acc.push(node);
10791
+ }
10792
+ } else if (node.type === "folder" && node.children) {
10793
+ const filteredChildren = filterTree(node.children, query);
10794
+ if (node.name.toLowerCase().includes(lowerQuery) || filteredChildren.length > 0) {
10795
+ acc.push(__spreadProps(__spreadValues({}, node), { children: filteredChildren }));
10796
+ }
10797
+ }
10798
+ return acc;
10799
+ }, []);
10800
+ }
10801
+ function getAllFolderPaths(nodes) {
10802
+ const paths = /* @__PURE__ */ new Set();
10803
+ function traverse(n) {
10804
+ for (const node of n) {
10805
+ if (node.type === "folder") {
10806
+ paths.add(node.path);
10807
+ if (node.children) traverse(node.children);
10808
+ }
10809
+ }
10810
+ }
10811
+ traverse(nodes);
10812
+ return paths;
10813
+ }
10761
10814
  var FileTreeExplorer = React3__namespace.memo(
10762
10815
  ({
10763
10816
  tree,
@@ -10770,6 +10823,16 @@ var FileTreeExplorer = React3__namespace.memo(
10770
10823
  headerClassName,
10771
10824
  className
10772
10825
  }) => {
10826
+ const [searchQuery, setSearchQuery] = React3__namespace.useState("");
10827
+ const filteredTree = React3__namespace.useMemo(() => {
10828
+ return filterTree(tree, searchQuery);
10829
+ }, [tree, searchQuery]);
10830
+ const expandedPaths = React3__namespace.useMemo(() => {
10831
+ if (searchQuery) {
10832
+ return getAllFolderPaths(filteredTree);
10833
+ }
10834
+ return defaultExpanded;
10835
+ }, [searchQuery, filteredTree, defaultExpanded]);
10773
10836
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col rounded-lg border bg-background", className), children: [
10774
10837
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-2 border-b px-3 py-2", headerClassName), children: [
10775
10838
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1", children: [
@@ -10785,6 +10848,8 @@ var FileTreeExplorer = React3__namespace.memo(
10785
10848
  Input2,
10786
10849
  {
10787
10850
  placeholder: searchPlaceholder,
10851
+ value: searchQuery,
10852
+ onChange: (e) => setSearchQuery(e.target.value),
10788
10853
  className: "pl-8"
10789
10854
  }
10790
10855
  )
@@ -10805,10 +10870,11 @@ var FileTreeExplorer = React3__namespace.memo(
10805
10870
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
10806
10871
  FileTree,
10807
10872
  {
10808
- defaultExpanded,
10873
+ className: "border-none bg-transparent",
10874
+ defaultExpanded: expandedPaths,
10809
10875
  selectedPath,
10810
10876
  onSelect,
10811
- children: renderTree(tree)
10877
+ children: renderTree(filteredTree)
10812
10878
  }
10813
10879
  ) })
10814
10880
  ] });
@@ -10901,11 +10967,14 @@ var AIDocEditor = React3__namespace.default.memo(
10901
10967
  }
10902
10968
  ) });
10903
10969
  }
10970
+ const { hideTabBar } = props;
10971
+ let editorPane;
10904
10972
  if (!currentDocument) {
10905
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("ai-doc-editor flex flex-col flex-1 h-screen w-full", className), children: [
10906
- /* @__PURE__ */ jsxRuntime.jsx(
10973
+ editorPane = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ai-doc-editor flex flex-col h-full w-full", children: [
10974
+ !hideTabBar && /* @__PURE__ */ jsxRuntime.jsx(
10907
10975
  DocumentTabBar,
10908
10976
  {
10977
+ className: "w-full",
10909
10978
  tabs: ((_a = props.documents) == null ? void 0 : _a.map((doc) => doc.file)) || [],
10910
10979
  activeTabId: props.activeDocumentId,
10911
10980
  onTabSelect: props.onTabSelect,
@@ -10914,42 +10983,44 @@ var AIDocEditor = React3__namespace.default.memo(
10914
10983
  ),
10915
10984
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center p-6 text-muted-foreground", children: "No documents open" })
10916
10985
  ] });
10986
+ } else {
10987
+ const isMarkdownMulti = currentDocument.file.format === "markdown";
10988
+ editorPane = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ai-doc-editor flex flex-col h-full w-full", children: [
10989
+ !hideTabBar && /* @__PURE__ */ jsxRuntime.jsx(
10990
+ DocumentTabBar,
10991
+ {
10992
+ className: "w-full",
10993
+ tabs: ((_b = props.documents) == null ? void 0 : _b.map((doc) => doc.file)) || [],
10994
+ activeTabId: props.activeDocumentId,
10995
+ onTabSelect: props.onTabSelect,
10996
+ onTabClose: props.onTabClose
10997
+ }
10998
+ ),
10999
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: isMarkdownMulti ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx(
11000
+ streamdown.Streamdown,
11001
+ {
11002
+ mode: "streaming",
11003
+ isAnimating: true,
11004
+ className: "[&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
11005
+ children: currentDocument.content
11006
+ }
11007
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(
11008
+ DocumentEditorWithComments,
11009
+ {
11010
+ content: currentDocument.content,
11011
+ format: currentDocument.file.format,
11012
+ annotations: currentDocument.annotations,
11013
+ selectedAnnotationId: props.selectedAnnotationId,
11014
+ currentUserId: currentUser2.id,
11015
+ currentUserName: currentUser2.name,
11016
+ readOnly: mode === "readonly",
11017
+ onAnnotationAdd: handleAnnotationAdd,
11018
+ onAnnotationUpdate: handleAnnotationUpdate,
11019
+ className: "ai-doc-editor p-6 min-h-full"
11020
+ }
11021
+ ) })
11022
+ ] });
10917
11023
  }
10918
- const isMarkdownMulti = currentDocument.file.format === "markdown";
10919
- const editorPane = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ai-doc-editor flex flex-col h-full w-full", children: [
10920
- /* @__PURE__ */ jsxRuntime.jsx(
10921
- DocumentTabBar,
10922
- {
10923
- className: "w-full",
10924
- tabs: ((_b = props.documents) == null ? void 0 : _b.map((doc) => doc.file)) || [],
10925
- activeTabId: props.activeDocumentId,
10926
- onTabSelect: props.onTabSelect,
10927
- onTabClose: props.onTabClose
10928
- }
10929
- ),
10930
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: isMarkdownMulti ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx(
10931
- streamdown.Streamdown,
10932
- {
10933
- mode: "streaming",
10934
- isAnimating: true,
10935
- className: "[&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
10936
- children: currentDocument.content
10937
- }
10938
- ) }) : /* @__PURE__ */ jsxRuntime.jsx(
10939
- DocumentEditorWithComments,
10940
- {
10941
- content: currentDocument.content,
10942
- format: currentDocument.file.format,
10943
- annotations: currentDocument.annotations,
10944
- currentUserId: currentUser2.id,
10945
- currentUserName: currentUser2.name,
10946
- readOnly: mode === "readonly",
10947
- onAnnotationAdd: handleAnnotationAdd,
10948
- onAnnotationUpdate: handleAnnotationUpdate,
10949
- className: "p-6 h-full flex flex-col"
10950
- }
10951
- ) })
10952
- ] });
10953
11024
  return /* @__PURE__ */ jsxRuntime.jsx(
10954
11025
  AdjustableLayout,
10955
11026
  {