@iloveagents/foundry-web-ui 0.3.1 → 0.5.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 (227) hide show
  1. package/README.md +13 -4
  2. package/dist/components/ag-ui-runtime-provider.d.ts +64 -0
  3. package/dist/components/ag-ui-runtime-provider.js +71 -0
  4. package/dist/components/app-brand.d.ts +6 -0
  5. package/dist/components/app-brand.js +13 -0
  6. package/dist/components/assistant-chat.d.ts +26 -0
  7. package/dist/components/assistant-chat.js +94 -0
  8. package/dist/components/chat-attachments.d.ts +25 -0
  9. package/dist/components/chat-attachments.js +20 -0
  10. package/dist/components/chat-bubble.d.ts +1 -0
  11. package/dist/components/chat-bubble.js +105 -0
  12. package/dist/components/chat-header.d.ts +2 -0
  13. package/dist/components/chat-header.js +16 -0
  14. package/dist/components/client-tool-executor.d.ts +12 -0
  15. package/dist/components/client-tool-executor.js +108 -0
  16. package/dist/components/collection-empty-state.d.ts +9 -0
  17. package/dist/components/collection-empty-state.js +6 -0
  18. package/dist/components/collection-filter-bar.d.ts +19 -0
  19. package/dist/components/collection-filter-bar.js +28 -0
  20. package/dist/components/collection-search-input.d.ts +6 -0
  21. package/dist/components/collection-search-input.js +8 -0
  22. package/dist/components/collection-skeleton.d.ts +6 -0
  23. package/dist/components/collection-skeleton.js +10 -0
  24. package/dist/components/collection-sort-menu.d.ts +10 -0
  25. package/dist/components/collection-sort-menu.js +9 -0
  26. package/dist/components/collection-surface.d.ts +8 -0
  27. package/dist/components/collection-surface.js +5 -0
  28. package/dist/components/collection-toolbar.d.ts +9 -0
  29. package/dist/components/collection-toolbar.js +5 -0
  30. package/dist/components/collection-view-toggle.d.ts +7 -0
  31. package/dist/components/collection-view-toggle.js +17 -0
  32. package/dist/components/composer-submit-bridge.d.ts +1 -0
  33. package/dist/components/composer-submit-bridge.js +15 -0
  34. package/dist/components/confirm-dialog.d.ts +11 -0
  35. package/dist/components/confirm-dialog.js +6 -0
  36. package/dist/components/confirmation-card.d.ts +14 -0
  37. package/dist/components/confirmation-card.js +12 -0
  38. package/dist/components/context-badges.d.ts +16 -0
  39. package/dist/components/context-badges.js +56 -0
  40. package/dist/components/context-bar.d.ts +41 -0
  41. package/dist/components/context-bar.js +123 -0
  42. package/dist/components/form-dialog.d.ts +12 -0
  43. package/dist/components/form-dialog.js +13 -0
  44. package/dist/components/global-selection-popover.d.ts +7 -0
  45. package/dist/components/global-selection-popover.js +167 -0
  46. package/dist/components/infinite-scroll-sentinel.d.ts +6 -0
  47. package/dist/components/infinite-scroll-sentinel.js +25 -0
  48. package/dist/components/json-viewer.d.ts +10 -0
  49. package/dist/components/json-viewer.js +80 -0
  50. package/dist/components/loading-indicator.d.ts +13 -0
  51. package/dist/components/loading-indicator.js +35 -0
  52. package/dist/components/markdown-text.d.ts +13 -0
  53. package/dist/components/markdown-text.js +221 -0
  54. package/dist/components/message-error.d.ts +10 -0
  55. package/dist/components/message-error.js +10 -0
  56. package/dist/components/message-timestamp.d.ts +10 -0
  57. package/dist/components/message-timestamp.js +18 -0
  58. package/dist/components/name-dialog.d.ts +16 -0
  59. package/dist/components/name-dialog.js +23 -0
  60. package/dist/components/selection-popover.d.ts +12 -0
  61. package/dist/components/selection-popover.js +111 -0
  62. package/dist/components/show-document-tool-ui.d.ts +1 -0
  63. package/dist/components/show-document-tool-ui.js +53 -0
  64. package/dist/components/sidebar.d.ts +4 -0
  65. package/dist/components/sidebar.js +904 -0
  66. package/dist/components/surface-card.d.ts +9 -0
  67. package/dist/components/surface-card.js +33 -0
  68. package/dist/components/theme-runtime-provider.d.ts +15 -0
  69. package/dist/components/theme-runtime-provider.js +48 -0
  70. package/dist/components/theme-toggle.d.ts +2 -0
  71. package/dist/components/theme-toggle.js +19 -0
  72. package/dist/components/tool-call-card.d.ts +27 -0
  73. package/dist/components/tool-call-card.js +13 -0
  74. package/dist/components/tool-fallback.d.ts +26 -0
  75. package/dist/components/tool-fallback.js +129 -0
  76. package/dist/components/tool-panel-layout.d.ts +10 -0
  77. package/dist/components/tool-panel-layout.js +12 -0
  78. package/dist/components/tool-panel.d.ts +1 -0
  79. package/dist/components/tool-panel.js +89 -0
  80. package/dist/components/tooltip-icon-button.d.ts +7 -0
  81. package/dist/components/tooltip-icon-button.js +9 -0
  82. package/dist/components/user-menu.d.ts +2 -0
  83. package/dist/components/user-menu.js +14 -0
  84. package/dist/index.d.ts +68 -0
  85. package/dist/index.js +83 -0
  86. package/dist/lib/ag-ui-adapter.d.ts +29 -0
  87. package/dist/lib/ag-ui-adapter.js +382 -0
  88. package/dist/lib/app-store.d.ts +115 -0
  89. package/dist/lib/app-store.js +199 -0
  90. package/dist/lib/attachment-adapter.d.ts +20 -0
  91. package/dist/lib/attachment-adapter.js +99 -0
  92. package/dist/lib/auth-provider.d.ts +16 -0
  93. package/dist/lib/auth-provider.js +88 -0
  94. package/dist/lib/chat-bubble-store.d.ts +30 -0
  95. package/dist/lib/chat-bubble-store.js +23 -0
  96. package/dist/lib/chat-lifecycle-store.d.ts +10 -0
  97. package/{src/lib/chat-lifecycle-store.ts → dist/lib/chat-lifecycle-store.js} +3 -13
  98. package/dist/lib/client-tools.d.ts +11 -0
  99. package/dist/lib/client-tools.js +274 -0
  100. package/dist/lib/composer-submit-store.d.ts +12 -0
  101. package/dist/lib/composer-submit-store.js +17 -0
  102. package/dist/lib/dev-store.d.ts +38 -0
  103. package/dist/lib/dev-store.js +32 -0
  104. package/dist/lib/nav-config.d.ts +159 -0
  105. package/dist/lib/nav-config.js +162 -0
  106. package/dist/lib/nav-dnd.d.ts +8 -0
  107. package/dist/lib/nav-dnd.js +9 -0
  108. package/dist/lib/nav-store.d.ts +45 -0
  109. package/dist/lib/nav-store.js +49 -0
  110. package/dist/lib/selection-context.d.ts +21 -0
  111. package/dist/lib/selection-context.js +34 -0
  112. package/dist/lib/sidebar-store.d.ts +23 -0
  113. package/dist/lib/sidebar-store.js +98 -0
  114. package/dist/lib/theme-runtime.d.ts +130 -0
  115. package/dist/lib/theme-runtime.js +479 -0
  116. package/dist/lib/theme-store.d.ts +15 -0
  117. package/dist/lib/theme-store.js +53 -0
  118. package/dist/lib/tool-panel-store.d.ts +48 -0
  119. package/dist/lib/tool-panel-store.js +69 -0
  120. package/dist/lib/use-new-conversation.d.ts +8 -0
  121. package/dist/lib/use-new-conversation.js +62 -0
  122. package/dist/lib/use-page-tools.d.ts +27 -0
  123. package/{src/lib/use-page-tools.ts → dist/lib/use-page-tools.js} +11 -13
  124. package/dist/styles.css +142 -0
  125. package/dist/ui/collapsible.d.ts +5 -0
  126. package/{src/ui/collapsible.tsx → dist/ui/collapsible.js} +0 -2
  127. package/dist/ui/dialog.d.ts +15 -0
  128. package/dist/ui/dialog.js +25 -0
  129. package/dist/ui/dropdown-menu.d.ts +7 -0
  130. package/dist/ui/dropdown-menu.js +19 -0
  131. package/dist/ui/popover.d.ts +7 -0
  132. package/dist/ui/popover.js +10 -0
  133. package/dist/ui/select.d.ts +4 -0
  134. package/dist/ui/select.js +9 -0
  135. package/dist/ui/tooltip.d.ts +7 -0
  136. package/dist/ui/tooltip.js +10 -0
  137. package/package.json +31 -12
  138. package/AGENTS.md +0 -59
  139. package/CHANGELOG.md +0 -211
  140. package/CLAUDE.md +0 -1
  141. package/src/__tests__/no-spaces-imports.test.ts +0 -59
  142. package/src/__tests__/open-core-guards.test.ts +0 -307
  143. package/src/__tests__/theme-runtime.test.ts +0 -81
  144. package/src/__tests__/tool-fallback.test.tsx +0 -109
  145. package/src/components/__tests__/context-bar.test.ts +0 -112
  146. package/src/components/ag-ui-runtime-provider.tsx +0 -170
  147. package/src/components/app-brand.tsx +0 -38
  148. package/src/components/assistant-chat.tsx +0 -461
  149. package/src/components/chat-attachments.tsx +0 -68
  150. package/src/components/chat-bubble.tsx +0 -373
  151. package/src/components/chat-header.tsx +0 -44
  152. package/src/components/client-tool-executor.tsx +0 -230
  153. package/src/components/collection-empty-state.tsx +0 -37
  154. package/src/components/collection-filter-bar.tsx +0 -168
  155. package/src/components/collection-search-input.tsx +0 -41
  156. package/src/components/collection-skeleton.tsx +0 -55
  157. package/src/components/collection-sort-menu.tsx +0 -62
  158. package/src/components/collection-surface.tsx +0 -46
  159. package/src/components/collection-toolbar.tsx +0 -33
  160. package/src/components/collection-view-toggle.tsx +0 -61
  161. package/src/components/composer-submit-bridge.tsx +0 -19
  162. package/src/components/confirm-dialog.tsx +0 -49
  163. package/src/components/confirmation-card.tsx +0 -32
  164. package/src/components/context-badges.tsx +0 -136
  165. package/src/components/context-bar.tsx +0 -238
  166. package/src/components/form-dialog.tsx +0 -56
  167. package/src/components/global-selection-popover.tsx +0 -266
  168. package/src/components/infinite-scroll-sentinel.tsx +0 -48
  169. package/src/components/json-viewer.tsx +0 -232
  170. package/src/components/loading-indicator.tsx +0 -40
  171. package/src/components/markdown-text-citations.test.tsx +0 -108
  172. package/src/components/markdown-text.tsx +0 -508
  173. package/src/components/name-dialog.tsx +0 -87
  174. package/src/components/selection-popover.tsx +0 -156
  175. package/src/components/show-document-tool-ui.tsx +0 -90
  176. package/src/components/sidebar.test.tsx +0 -611
  177. package/src/components/sidebar.tsx +0 -1689
  178. package/src/components/surface-card.tsx +0 -45
  179. package/src/components/theme-runtime-provider.tsx +0 -93
  180. package/src/components/theme-toggle.tsx +0 -27
  181. package/src/components/tool-call-card.tsx +0 -126
  182. package/src/components/tool-fallback.tsx +0 -169
  183. package/src/components/tool-panel-layout.tsx +0 -36
  184. package/src/components/tool-panel.tsx +0 -233
  185. package/src/components/tooltip-icon-button.tsx +0 -28
  186. package/src/components/user-menu.tsx +0 -60
  187. package/src/index.ts +0 -185
  188. package/src/lib/__tests__/ag-ui-adapter.test.ts +0 -279
  189. package/src/lib/__tests__/app-store.test.ts +0 -405
  190. package/src/lib/__tests__/attachment-adapter.test.ts +0 -48
  191. package/src/lib/__tests__/chat-bubble-store.test.ts +0 -67
  192. package/src/lib/__tests__/client-tools.test.ts +0 -124
  193. package/src/lib/__tests__/dev-store.test.ts +0 -78
  194. package/src/lib/__tests__/nav-config.test.ts +0 -135
  195. package/src/lib/__tests__/nav-dnd.test.ts +0 -24
  196. package/src/lib/__tests__/nav-store.test.ts +0 -59
  197. package/src/lib/__tests__/selection-context.test.ts +0 -114
  198. package/src/lib/__tests__/sidebar-store.test.ts +0 -144
  199. package/src/lib/__tests__/theme-store.test.ts +0 -83
  200. package/src/lib/__tests__/tool-panel-store.test.ts +0 -61
  201. package/src/lib/__tests__/use-page-context.test.ts +0 -58
  202. package/src/lib/ag-ui-adapter.ts +0 -426
  203. package/src/lib/app-store.ts +0 -361
  204. package/src/lib/attachment-adapter.ts +0 -92
  205. package/src/lib/auth-provider.tsx +0 -144
  206. package/src/lib/chat-bubble-store.ts +0 -46
  207. package/src/lib/client-tools.ts +0 -293
  208. package/src/lib/composer-submit-store.ts +0 -32
  209. package/src/lib/dev-store.ts +0 -69
  210. package/src/lib/nav-config.ts +0 -329
  211. package/src/lib/nav-dnd.ts +0 -14
  212. package/src/lib/nav-store.ts +0 -89
  213. package/src/lib/selection-context.ts +0 -65
  214. package/src/lib/sidebar-store.ts +0 -113
  215. package/src/lib/theme-runtime.ts +0 -660
  216. package/src/lib/theme-store.ts +0 -67
  217. package/src/lib/tool-panel-store.ts +0 -121
  218. package/src/lib/use-new-conversation.test.tsx +0 -168
  219. package/src/lib/use-new-conversation.ts +0 -64
  220. package/src/ui/dialog.tsx +0 -109
  221. package/src/ui/dropdown-menu.tsx +0 -75
  222. package/src/ui/popover.tsx +0 -34
  223. package/src/ui/select.tsx +0 -15
  224. package/src/ui/tooltip.tsx +0 -30
  225. package/src/vite-env.d.ts +0 -1
  226. package/tsconfig.json +0 -16
  227. package/vitest.config.ts +0 -8
@@ -1,461 +0,0 @@
1
- import { type FC, useState, useRef, useCallback } from "react";
2
- import {
3
- ThreadPrimitive,
4
- ComposerPrimitive,
5
- MessagePrimitive,
6
- ActionBarPrimitive,
7
- BranchPickerPrimitive,
8
- ErrorPrimitive,
9
- useAuiState,
10
- useComposerRuntime,
11
- useThreadViewport,
12
- } from "@assistant-ui/react";
13
- import {
14
- ArrowUp,
15
- Copy,
16
- Check,
17
- RefreshCw,
18
- PencilIcon,
19
- ChevronLeft,
20
- ChevronRight,
21
- ChevronDown,
22
- Square,
23
- Bot,
24
- Paperclip,
25
- Minimize2,
26
- PanelRightClose,
27
- PanelRightOpen,
28
- } from "lucide-react";
29
- import { cn } from "@iloveagents/foundry-web-primitives";
30
- import { Button } from "@iloveagents/foundry-web-primitives";
31
- import { TooltipIconButton } from "./tooltip-icon-button.tsx";
32
- import { userAttachmentComponents, composerAttachmentComponents } from "./chat-attachments.tsx";
33
- import { SentContextBadges, ComposerContextBadges } from "./context-badges.tsx";
34
- import { ContextPins } from "./context-bar.tsx";
35
- import { ComposerSubmitBridge } from "./composer-submit-bridge.tsx";
36
- import { useChatBubbleStore } from "../lib/chat-bubble-store.ts";
37
- import { MarkdownText } from "./markdown-text.tsx";
38
- import { ToolFallback } from "./tool-fallback.tsx";
39
- import { LoadingIndicator, LoadingBar } from "./loading-indicator.tsx";
40
-
41
- const BranchPicker: FC = () => (
42
- <BranchPickerPrimitive.Root
43
- hideWhenSingleBranch
44
- className="inline-flex items-center gap-1 text-xs"
45
- >
46
- <BranchPickerPrimitive.Previous asChild>
47
- <TooltipIconButton tooltip="Previous" size="icon">
48
- <ChevronLeft className="size-4" />
49
- </TooltipIconButton>
50
- </BranchPickerPrimitive.Previous>
51
- <span className="text-muted-foreground">
52
- <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
53
- </span>
54
- <BranchPickerPrimitive.Next asChild>
55
- <TooltipIconButton tooltip="Next" size="icon">
56
- <ChevronRight className="size-4" />
57
- </TooltipIconButton>
58
- </BranchPickerPrimitive.Next>
59
- </BranchPickerPrimitive.Root>
60
- );
61
-
62
- const UserMessage: FC = () => {
63
- const messageId = useAuiState((s) => s.message.id);
64
-
65
- return (
66
- <MessagePrimitive.Root className="w-full mb-2 group">
67
- <div className="flex flex-col items-end gap-1">
68
- <MessagePrimitive.Attachments components={userAttachmentComponents} />
69
- <SentContextBadges messageId={messageId} />
70
- <div className={cn("max-w-[80%]", "bg-muted rounded-2xl", "px-4 py-3", "text-foreground")}>
71
- <MessagePrimitive.Content />
72
- </div>
73
- <div className="flex items-center justify-end gap-2 pr-2">
74
- <BranchPicker />
75
- <div className="w-10 flex items-center justify-end">
76
- <UserActionBar />
77
- </div>
78
- </div>
79
- </div>
80
- </MessagePrimitive.Root>
81
- );
82
- };
83
-
84
- const UserActionBar: FC = () => (
85
- <ActionBarPrimitive.Root
86
- hideWhenRunning
87
- className="flex items-center opacity-0 group-hover:opacity-100 transition-opacity"
88
- >
89
- <ActionBarPrimitive.Edit asChild>
90
- <TooltipIconButton tooltip="Edit" size="icon">
91
- <PencilIcon className="size-4" />
92
- </TooltipIconButton>
93
- </ActionBarPrimitive.Edit>
94
- </ActionBarPrimitive.Root>
95
- );
96
-
97
- const AssistantMessage: FC = () => (
98
- <MessagePrimitive.Root className="w-full mb-2 group">
99
- <div className="mx-auto max-w-3xl px-4">
100
- <div className="text-foreground leading-relaxed flex flex-col gap-4">
101
- <MessagePrimitive.Parts
102
- components={{
103
- Text: MarkdownText,
104
- tools: { Fallback: ToolFallback },
105
- }}
106
- />
107
- </div>
108
- <MessageError />
109
-
110
- <div className="flex items-center gap-2 mt-1">
111
- <div className="flex h-8 w-[4.25rem] items-center">
112
- <AssistantActionBar />
113
- </div>
114
- <BranchPicker />
115
- </div>
116
- </div>
117
- </MessagePrimitive.Root>
118
- );
119
-
120
- const AssistantActionBar: FC = () => (
121
- <ActionBarPrimitive.Root
122
- hideWhenRunning
123
- className={cn(
124
- "pointer-events-none flex items-center gap-1 -ml-2 opacity-0 transition-opacity",
125
- "group-hover:pointer-events-auto group-hover:opacity-100",
126
- "group-focus-within:pointer-events-auto group-focus-within:opacity-100",
127
- )}
128
- >
129
- <ActionBarPrimitive.Copy asChild>
130
- <TooltipIconButton tooltip="Copy" size="icon">
131
- <MessagePrimitive.If copied={false}>
132
- <Copy className="size-4" />
133
- </MessagePrimitive.If>
134
- <MessagePrimitive.If copied>
135
- <Check className="size-4 text-primary" />
136
- </MessagePrimitive.If>
137
- </TooltipIconButton>
138
- </ActionBarPrimitive.Copy>
139
- <ActionBarPrimitive.Reload asChild>
140
- <TooltipIconButton tooltip="Refresh" size="icon">
141
- <RefreshCw className="size-4" />
142
- </TooltipIconButton>
143
- </ActionBarPrimitive.Reload>
144
- </ActionBarPrimitive.Root>
145
- );
146
-
147
- const MessageError: FC = () => (
148
- <MessagePrimitive.Error>
149
- <ErrorPrimitive.Root className="mt-2 rounded-lg border border-destructive bg-destructive/10 p-3">
150
- <div className="flex items-center gap-2">
151
- <span className="text-sm font-medium text-destructive">Error:</span>
152
- <ErrorPrimitive.Message className="text-sm text-destructive" />
153
- </div>
154
- </ErrorPrimitive.Root>
155
- </MessagePrimitive.Error>
156
- );
157
-
158
- const EditComposer: FC = () => (
159
- <MessagePrimitive.Root className="w-full mb-2">
160
- <div className="flex items-start justify-end">
161
- <div className="w-full max-w-[80%]">
162
- <ComposerPrimitive.Root
163
- className={cn(
164
- "flex flex-col gap-2",
165
- "rounded-2xl border border-input",
166
- "bg-background shadow-sm",
167
- "px-4 py-3",
168
- )}
169
- >
170
- <ComposerPrimitive.Input
171
- autoFocus
172
- className={cn(
173
- "w-full bg-transparent",
174
- "text-base text-foreground",
175
- "outline-none resize-none",
176
- "placeholder:text-muted-foreground",
177
- )}
178
- />
179
- <div className="flex items-center justify-end gap-2">
180
- <ComposerPrimitive.Cancel asChild>
181
- <Button variant="ghost" size="sm">
182
- Cancel
183
- </Button>
184
- </ComposerPrimitive.Cancel>
185
- <ComposerPrimitive.Send asChild>
186
- <Button size="sm">Update</Button>
187
- </ComposerPrimitive.Send>
188
- </div>
189
- </ComposerPrimitive.Root>
190
- </div>
191
- </div>
192
- </MessagePrimitive.Root>
193
- );
194
-
195
- const ComposerActionButton: FC = () => {
196
- return (
197
- <>
198
- <ThreadPrimitive.If running>
199
- <ComposerPrimitive.Cancel asChild>
200
- <Button
201
- variant="secondary"
202
- size="icon"
203
- className="rounded-full size-10 flex-shrink-0"
204
- aria-label="Stop generating"
205
- >
206
- <Square className="size-4" />
207
- </Button>
208
- </ComposerPrimitive.Cancel>
209
- </ThreadPrimitive.If>
210
-
211
- <ThreadPrimitive.If running={false}>
212
- <ComposerPrimitive.Send asChild>
213
- <Button
214
- size="icon"
215
- className="rounded-full size-10 flex-shrink-0"
216
- aria-label="Send message"
217
- >
218
- <ArrowUp className="size-5" />
219
- </Button>
220
- </ComposerPrimitive.Send>
221
- </ThreadPrimitive.If>
222
- </>
223
- );
224
- };
225
-
226
- /**
227
- * Default starter prompts shown on empty state. Override per-app by passing
228
- * a `starterSuggestions` prop to `<ChatContent>`. An empty array (`[]`)
229
- * suppresses the suggestion buttons entirely.
230
- */
231
- export const DEFAULT_STARTER_SUGGESTIONS = [
232
- "Create a new Contract Space",
233
- "List all contracts I have access to",
234
- "Show me what I can do here",
235
- ];
236
-
237
- const ScrollToBottomButton: FC = () => {
238
- const isAtBottom = useThreadViewport((s) => s.isAtBottom);
239
- const scrollToBottom = useThreadViewport((s) => s.scrollToBottom);
240
-
241
- if (isAtBottom) return null;
242
-
243
- return (
244
- <Button
245
- variant="outline"
246
- size="icon"
247
- className="absolute bottom-4 left-1/2 -translate-x-1/2 z-10 rounded-full shadow-md"
248
- onClick={() => scrollToBottom({ behavior: "smooth" })}
249
- >
250
- <ChevronDown className="size-4" />
251
- </Button>
252
- );
253
- };
254
-
255
- const DropZone: FC<{ children: React.ReactNode }> = ({ children }) => {
256
- const [isDragging, setIsDragging] = useState(false);
257
- const dragCounter = useRef(0);
258
- const composerRuntime = useComposerRuntime();
259
-
260
- const handleDragEnter = useCallback((e: React.DragEvent) => {
261
- e.preventDefault();
262
- dragCounter.current++;
263
- if (dragCounter.current === 1) setIsDragging(true);
264
- }, []);
265
-
266
- const handleDragLeave = useCallback((e: React.DragEvent) => {
267
- e.preventDefault();
268
- dragCounter.current--;
269
- if (dragCounter.current === 0) setIsDragging(false);
270
- }, []);
271
-
272
- const handleDragOver = useCallback((e: React.DragEvent) => {
273
- e.preventDefault();
274
- }, []);
275
-
276
- const handleDrop = useCallback(
277
- async (e: React.DragEvent) => {
278
- e.preventDefault();
279
- dragCounter.current = 0;
280
- setIsDragging(false);
281
- const files = Array.from(e.dataTransfer.files);
282
- for (const file of files) {
283
- await composerRuntime.addAttachment(file);
284
- }
285
- },
286
- [composerRuntime],
287
- );
288
-
289
- return (
290
- <div
291
- className="relative flex flex-col flex-1 overflow-hidden"
292
- onDragEnter={handleDragEnter}
293
- onDragLeave={handleDragLeave}
294
- onDragOver={handleDragOver}
295
- onDrop={handleDrop}
296
- >
297
- {children}
298
- {isDragging && (
299
- <div
300
- className={cn(
301
- "absolute inset-0 z-50 flex items-center justify-center pointer-events-none",
302
- "bg-background/80 backdrop-blur-sm",
303
- "border-2 border-dashed border-primary rounded-xl",
304
- )}
305
- >
306
- <p className="text-lg text-primary font-medium">Drop files here</p>
307
- </div>
308
- )}
309
- </div>
310
- );
311
- };
312
-
313
- export interface ChatContentProps {
314
- /**
315
- * Starter prompts shown when the thread is empty. Defaults to
316
- * `DEFAULT_STARTER_SUGGESTIONS`. Pass an empty array to hide the
317
- * suggestion buttons entirely. Customer apps (e.g. ANDRITZ Contracts)
318
- * can pass a workspace-aware list derived from app context.
319
- */
320
- starterSuggestions?: string[];
321
- }
322
-
323
- /**
324
- * Reusable chat content — used by ChatPage and ChatBubble.
325
- * Renders inside a ThreadPrimitive.Root context.
326
- */
327
- export function ChatContent({
328
- starterSuggestions = DEFAULT_STARTER_SUGGESTIONS,
329
- }: ChatContentProps = {}) {
330
- const isExpanded = useChatBubbleStore((s) => s.isExpanded);
331
- const collapseChat = useChatBubbleStore((s) => s.collapse);
332
- const showPagePanel = useChatBubbleStore((s) => s.showPagePanel);
333
- const togglePagePanel = useChatBubbleStore((s) => s.togglePagePanel);
334
-
335
- return (
336
- <ThreadPrimitive.Root
337
- className={cn("flex flex-col flex-1", "bg-background text-foreground", "overflow-hidden")}
338
- >
339
- {/* Collapse header — only in expanded layout mode */}
340
- {isExpanded && (
341
- <div className="shrink-0 flex items-center justify-between px-4 py-2 border-b border-border">
342
- <span className="text-sm font-medium text-foreground flex items-center gap-2">
343
- <Bot className="size-4 text-primary" />
344
- Chat
345
- </span>
346
- <div className="flex items-center gap-1">
347
- <TooltipIconButton
348
- tooltip={showPagePanel ? "Hide page panel" : "Show page panel"}
349
- size="icon"
350
- onClick={togglePagePanel}
351
- className="hidden xl:inline-flex"
352
- >
353
- {showPagePanel ? (
354
- <PanelRightClose className="size-4" />
355
- ) : (
356
- <PanelRightOpen className="size-4" />
357
- )}
358
- </TooltipIconButton>
359
- <TooltipIconButton tooltip="Minimize to bubble" size="icon" onClick={collapseChat}>
360
- <Minimize2 className="size-4" />
361
- </TooltipIconButton>
362
- </div>
363
- </div>
364
- )}
365
- <DropZone>
366
- <div className="relative flex-1 overflow-hidden">
367
- <ThreadPrimitive.Viewport className="absolute inset-0 overflow-y-auto bg-background">
368
- <ThreadPrimitive.Empty>
369
- <div
370
- className={cn("flex min-h-full flex-col", "items-center justify-center", "px-4")}
371
- >
372
- <Bot className="size-16 mb-6 text-primary/70" />
373
- <h1 className="text-[2rem] font-normal text-foreground text-center mb-6">
374
- How can I help you today?
375
- </h1>
376
- {starterSuggestions.length > 0 && (
377
- <div className="flex flex-wrap justify-center gap-2 max-w-lg">
378
- {starterSuggestions.map((prompt) => (
379
- <ThreadPrimitive.Suggestion key={prompt} prompt={prompt} send asChild>
380
- <Button variant="outline" className="text-sm">
381
- {prompt}
382
- </Button>
383
- </ThreadPrimitive.Suggestion>
384
- ))}
385
- </div>
386
- )}
387
- </div>
388
- </ThreadPrimitive.Empty>
389
-
390
- <ThreadPrimitive.If empty={false}>
391
- <div className="mx-auto max-w-3xl px-4 pt-8">
392
- <ThreadPrimitive.Messages
393
- components={{
394
- UserMessage,
395
- EditComposer,
396
- AssistantMessage,
397
- }}
398
- />
399
- <ThreadPrimitive.If running>
400
- <LoadingIndicator />
401
- </ThreadPrimitive.If>
402
- </div>
403
- </ThreadPrimitive.If>
404
- </ThreadPrimitive.Viewport>
405
- <ThreadPrimitive.If empty={false}>
406
- <ScrollToBottomButton />
407
- </ThreadPrimitive.If>
408
- </div>
409
-
410
- <div className="shrink-0 bg-background">
411
- <ThreadPrimitive.If running={false}>
412
- <div className="border-t border-border" />
413
- </ThreadPrimitive.If>
414
- <ThreadPrimitive.If running>
415
- <LoadingBar />
416
- </ThreadPrimitive.If>
417
-
418
- <div className="mx-auto max-w-3xl px-4 py-4">
419
- <ComposerPrimitive.Root
420
- className={cn(
421
- "flex flex-col gap-2",
422
- "rounded-3xl border border-input",
423
- "bg-background shadow-sm",
424
- "px-4 py-2",
425
- "focus-within:border-primary/50 focus-within:shadow-md",
426
- "transition-all duration-300",
427
- )}
428
- >
429
- <ComposerSubmitBridge />
430
- <ComposerContextBadges />
431
- <ComposerPrimitive.Attachments components={composerAttachmentComponents} />
432
- <div className="flex items-center gap-2">
433
- <div className="flex items-center -space-x-1 shrink-0">
434
- <ComposerPrimitive.AddAttachment asChild>
435
- <TooltipIconButton tooltip="Attach file" variant="ghost" className="shrink-0">
436
- <Paperclip className="size-5" />
437
- </TooltipIconButton>
438
- </ComposerPrimitive.AddAttachment>
439
- <ContextPins showPinButton />
440
- </div>
441
- <ComposerPrimitive.Input
442
- autoFocus
443
- placeholder="Message Assistant..."
444
- rows={1}
445
- className={cn(
446
- "flex-1 bg-transparent",
447
- "py-2 text-base",
448
- "text-foreground outline-none",
449
- "placeholder:text-muted-foreground",
450
- "resize-none max-h-32",
451
- )}
452
- />
453
- <ComposerActionButton />
454
- </div>
455
- </ComposerPrimitive.Root>
456
- </div>
457
- </div>
458
- </DropZone>
459
- </ThreadPrimitive.Root>
460
- );
461
- }
@@ -1,68 +0,0 @@
1
- /**
2
- * Attachment rendering components for chat messages and composer.
3
- *
4
- * Following the official assistant-ui pattern, attachment components
5
- * live in a separate file from the main thread components.
6
- *
7
- * @see https://www.assistant-ui.com/ - assistant-ui Documentation
8
- */
9
-
10
- import { type FC } from "react";
11
- import { AttachmentPrimitive } from "@assistant-ui/react";
12
- import { FileText, X } from "lucide-react";
13
- import { cn } from "@iloveagents/foundry-web-primitives";
14
-
15
- /** Renders a pending file attachment chip in the composer with a remove button. */
16
- export const ComposerAttachment: FC = () => (
17
- <AttachmentPrimitive.Root
18
- className={cn(
19
- "inline-flex items-center gap-2 max-w-[250px]",
20
- "rounded-lg border border-border bg-muted/50",
21
- "px-3 py-2",
22
- )}
23
- >
24
- <FileText className="size-4 text-muted-foreground flex-shrink-0" />
25
- <span className="text-sm truncate">
26
- <AttachmentPrimitive.Name />
27
- </span>
28
- <AttachmentPrimitive.Remove asChild>
29
- <button
30
- type="button"
31
- className="p-0.5 rounded hover:bg-muted flex-shrink-0"
32
- aria-label="Remove attachment"
33
- >
34
- <X className="size-3.5" />
35
- </button>
36
- </AttachmentPrimitive.Remove>
37
- </AttachmentPrimitive.Root>
38
- );
39
-
40
- /** Renders a file badge on sent user messages. */
41
- export const UserMessageAttachment: FC = () => (
42
- <AttachmentPrimitive.Root
43
- className={cn(
44
- "inline-flex items-center gap-2 max-w-[250px]",
45
- "rounded-lg border border-border/50 bg-muted/30",
46
- "px-3 py-1.5",
47
- )}
48
- >
49
- <FileText className="size-3.5 text-muted-foreground flex-shrink-0" />
50
- <span className="text-xs truncate">
51
- <AttachmentPrimitive.Name />
52
- </span>
53
- </AttachmentPrimitive.Root>
54
- );
55
-
56
- /** Component map for MessagePrimitive.Attachments on user messages. */
57
- export const userAttachmentComponents = {
58
- Document: UserMessageAttachment,
59
- Image: UserMessageAttachment,
60
- File: UserMessageAttachment,
61
- };
62
-
63
- /** Component map for ComposerPrimitive.Attachments in the composer. */
64
- export const composerAttachmentComponents = {
65
- Document: ComposerAttachment,
66
- Image: ComposerAttachment,
67
- File: ComposerAttachment,
68
- };