ai-design-system 0.1.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 (290) hide show
  1. package/README.md +307 -0
  2. package/components/ai-elements/actions.tsx +65 -0
  3. package/components/ai-elements/artifact.tsx +147 -0
  4. package/components/ai-elements/branch.tsx +212 -0
  5. package/components/ai-elements/canvas.tsx +24 -0
  6. package/components/ai-elements/chain-of-thought.tsx +228 -0
  7. package/components/ai-elements/code-block.tsx +179 -0
  8. package/components/ai-elements/confirmation.tsx +169 -0
  9. package/components/ai-elements/connection.tsx +28 -0
  10. package/components/ai-elements/context.tsx +408 -0
  11. package/components/ai-elements/controls.tsx +18 -0
  12. package/components/ai-elements/conversation.tsx +97 -0
  13. package/components/ai-elements/edge.tsx +140 -0
  14. package/components/ai-elements/image.tsx +24 -0
  15. package/components/ai-elements/inline-citation.tsx +287 -0
  16. package/components/ai-elements/loader.tsx +96 -0
  17. package/components/ai-elements/message.tsx +80 -0
  18. package/components/ai-elements/node.tsx +71 -0
  19. package/components/ai-elements/open-in-chat.tsx +363 -0
  20. package/components/ai-elements/panel.tsx +15 -0
  21. package/components/ai-elements/plan.tsx +142 -0
  22. package/components/ai-elements/prompt-input.tsx +1352 -0
  23. package/components/ai-elements/queue.tsx +274 -0
  24. package/components/ai-elements/reasoning.tsx +178 -0
  25. package/components/ai-elements/response.tsx +22 -0
  26. package/components/ai-elements/shimmer.tsx +64 -0
  27. package/components/ai-elements/sources.tsx +77 -0
  28. package/components/ai-elements/suggestion.tsx +56 -0
  29. package/components/ai-elements/task.tsx +87 -0
  30. package/components/ai-elements/tool.tsx +179 -0
  31. package/components/ai-elements/toolbar.tsx +16 -0
  32. package/components/ai-elements/web-preview.tsx +263 -0
  33. package/components/blocks/AIConversation/AIConversation.stories.tsx +164 -0
  34. package/components/blocks/AIConversation/AIConversation.tsx +186 -0
  35. package/components/blocks/AIConversation/index.ts +8 -0
  36. package/components/blocks/AppSidebar/AppSidebar.stories.tsx +63 -0
  37. package/components/blocks/AppSidebar/AppSidebar.tsx +87 -0
  38. package/components/blocks/AppSidebar/index.ts +2 -0
  39. package/components/blocks/DocumentEditorWithComments/DocumentEditorWithComments.stories.tsx +341 -0
  40. package/components/blocks/DocumentEditorWithComments/DocumentEditorWithComments.tsx +255 -0
  41. package/components/blocks/DocumentEditorWithComments/index.ts +9 -0
  42. package/components/blocks/FileChangeQueue/FileChangeQueue.stories.tsx +207 -0
  43. package/components/blocks/FileChangeQueue/FileChangeQueue.tsx +143 -0
  44. package/components/blocks/FileChangeQueue/index.ts +7 -0
  45. package/components/blocks/LayoutProvider/LayoutProvider.tsx +34 -0
  46. package/components/blocks/LayoutProvider/index.ts +1 -0
  47. package/components/blocks/index.ts +2 -0
  48. package/components/composites/AgentIndicator/AgentIndicator.stories.tsx +154 -0
  49. package/components/composites/AgentIndicator/AgentIndicator.tsx +102 -0
  50. package/components/composites/AgentIndicator/index.ts +8 -0
  51. package/components/composites/AppHeader/AppHeader.stories.tsx +46 -0
  52. package/components/composites/AppHeader/AppHeader.tsx +24 -0
  53. package/components/composites/AppHeader/index.ts +2 -0
  54. package/components/composites/CommentBox/CommentBox.stories.tsx +192 -0
  55. package/components/composites/CommentBox/CommentBox.tsx +364 -0
  56. package/components/composites/CommentBox/index.ts +8 -0
  57. package/components/composites/Confirmation/Confirmation.stories.tsx +151 -0
  58. package/components/composites/Confirmation/Confirmation.tsx +93 -0
  59. package/components/composites/Confirmation/index.ts +7 -0
  60. package/components/composites/DataTable/DataTable.stories.tsx +35 -0
  61. package/components/composites/DataTable/DataTable.tsx +95 -0
  62. package/components/composites/DataTable/index.ts +2 -0
  63. package/components/composites/DocumentEditor/DocumentEditor.css +106 -0
  64. package/components/composites/DocumentEditor/DocumentEditor.stories.tsx +927 -0
  65. package/components/composites/DocumentEditor/DocumentEditor.tsx +279 -0
  66. package/components/composites/DocumentEditor/index.ts +8 -0
  67. package/components/composites/FileQueue/FileQueue.stories.tsx +175 -0
  68. package/components/composites/FileQueue/FileQueue.tsx +161 -0
  69. package/components/composites/FileQueue/FileStatusBadge.tsx +74 -0
  70. package/components/composites/FileQueue/index.ts +24 -0
  71. package/components/composites/InteractiveChart/InteractiveChart.stories.tsx +49 -0
  72. package/components/composites/InteractiveChart/InteractiveChart.tsx +69 -0
  73. package/components/composites/InteractiveChart/index.ts +2 -0
  74. package/components/composites/ModeToggle/ModeToggle.stories.tsx +212 -0
  75. package/components/composites/ModeToggle/ModeToggle.tsx +100 -0
  76. package/components/composites/ModeToggle/index.ts +7 -0
  77. package/components/composites/NavUser/NavUser.stories.tsx +50 -0
  78. package/components/composites/NavUser/NavUser.tsx +60 -0
  79. package/components/composites/NavUser/index.ts +2 -0
  80. package/components/composites/NavigationList/NavigationList.stories.tsx +46 -0
  81. package/components/composites/NavigationList/NavigationList.tsx +46 -0
  82. package/components/composites/NavigationList/index.ts +2 -0
  83. package/components/composites/OrchestratorMessage/OrchestratorMessage.stories.tsx +188 -0
  84. package/components/composites/OrchestratorMessage/OrchestratorMessage.tsx +72 -0
  85. package/components/composites/OrchestratorMessage/index.ts +8 -0
  86. package/components/composites/PageContainer/PageContainer.stories.tsx +41 -0
  87. package/components/composites/PageContainer/PageContainer.tsx +24 -0
  88. package/components/composites/PageContainer/index.ts +2 -0
  89. package/components/composites/PromptInput/PromptInput.stories.tsx +200 -0
  90. package/components/composites/PromptInput/PromptInput.tsx +129 -0
  91. package/components/composites/PromptInput/index.ts +8 -0
  92. package/components/composites/SpecialistMessage/SpecialistMessage.stories.tsx +286 -0
  93. package/components/composites/SpecialistMessage/SpecialistMessage.tsx +107 -0
  94. package/components/composites/SpecialistMessage/index.ts +8 -0
  95. package/components/composites/StatsCard/StatsCard.stories.tsx +76 -0
  96. package/components/composites/StatsCard/StatsCard.tsx +81 -0
  97. package/components/composites/StatsCard/index.ts +2 -0
  98. package/components/composites/TablePagination/TablePagination.stories.tsx +38 -0
  99. package/components/composites/TablePagination/TablePagination.tsx +119 -0
  100. package/components/composites/TablePagination/index.ts +2 -0
  101. package/components/composites/TableToolbar/TableToolbar.stories.tsx +60 -0
  102. package/components/composites/TableToolbar/TableToolbar.tsx +66 -0
  103. package/components/composites/TableToolbar/index.ts +2 -0
  104. package/components/composites/ThemeSelector/ThemeSelector.stories.tsx +48 -0
  105. package/components/composites/ThemeSelector/ThemeSelector.tsx +79 -0
  106. package/components/composites/ThemeSelector/index.ts +2 -0
  107. package/components/composites/ToolCallDisplay/ToolCallDisplay.stories.tsx +49 -0
  108. package/components/composites/ToolCallDisplay/ToolCallDisplay.tsx +108 -0
  109. package/components/composites/ToolCallDisplay/index.ts +8 -0
  110. package/components/composites/UserMessage/UserMessage.stories.tsx +59 -0
  111. package/components/composites/UserMessage/UserMessage.tsx +52 -0
  112. package/components/composites/UserMessage/index.ts +8 -0
  113. package/components/composites/index.ts +90 -0
  114. package/components/features/AIDocEditor/AIDocEditor.behaviors.stories.tsx +451 -0
  115. package/components/features/AIDocEditor/AIDocEditor.mocks.ts +96 -0
  116. package/components/features/AIDocEditor/AIDocEditor.stories.tsx +140 -0
  117. package/components/features/AIDocEditor/AIDocEditor.tsx +130 -0
  118. package/components/features/AIDocEditor/index.ts +8 -0
  119. package/components/features/AIDocEditor/useAIDocEditor.d.ts +97 -0
  120. package/components/features/AIDocEditor/useAIDocEditor.mock.ts +83 -0
  121. package/components/features/PageLayout/PageLayout.behaviors.stories.tsx +119 -0
  122. package/components/features/PageLayout/PageLayout.mocks.ts +27 -0
  123. package/components/features/PageLayout/PageLayout.stories.tsx +142 -0
  124. package/components/features/PageLayout/PageLayout.tsx +94 -0
  125. package/components/features/PageLayout/index.ts +4 -0
  126. package/components/features/PageLayout/usePageLayout.d.ts +24 -0
  127. package/components/features/PageLayout/usePageLayout.mock.ts +19 -0
  128. package/components/features/RefinementPanel/README.md +189 -0
  129. package/components/features/RefinementPanel/RefinementPanel.behaviors.stories.tsx +475 -0
  130. package/components/features/RefinementPanel/RefinementPanel.mocks.ts +131 -0
  131. package/components/features/RefinementPanel/RefinementPanel.stories.tsx +141 -0
  132. package/components/features/RefinementPanel/RefinementPanel.tsx +160 -0
  133. package/components/features/RefinementPanel/index.ts +25 -0
  134. package/components/features/RefinementPanel/useRefinementPanel.d.ts +74 -0
  135. package/components/features/RefinementPanel/useRefinementPanel.mock.ts +121 -0
  136. package/components/features/SpecNavigator/SpecNavigator.behaviors.stories.tsx +379 -0
  137. package/components/features/SpecNavigator/SpecNavigator.mocks.ts +131 -0
  138. package/components/features/SpecNavigator/SpecNavigator.stories.tsx +122 -0
  139. package/components/features/SpecNavigator/SpecNavigator.tsx +43 -0
  140. package/components/features/SpecNavigator/index.ts +2 -0
  141. package/components/features/SpecNavigator/useSpecNavigator.d.ts +122 -0
  142. package/components/features/SpecNavigator/useSpecNavigator.mock.ts +93 -0
  143. package/components/features/index.ts +18 -0
  144. package/components/index.ts +14 -0
  145. package/components/primitives/Accordion/Accordion.stories.tsx +87 -0
  146. package/components/primitives/Accordion/Accordion.tsx +66 -0
  147. package/components/primitives/Accordion/index.ts +13 -0
  148. package/components/primitives/Alert/Alert.stories.tsx +422 -0
  149. package/components/primitives/Alert/Alert.tsx +61 -0
  150. package/components/primitives/Alert/index.ts +8 -0
  151. package/components/primitives/AlertDialog/AlertDialog.stories.tsx +367 -0
  152. package/components/primitives/AlertDialog/AlertDialog.tsx +182 -0
  153. package/components/primitives/AlertDialog/index.ts +25 -0
  154. package/components/primitives/Avatar/Avatar.stories.tsx +321 -0
  155. package/components/primitives/Avatar/Avatar.tsx +63 -0
  156. package/components/primitives/Avatar/index.ts +8 -0
  157. package/components/primitives/Badge/Badge.stories.tsx +74 -0
  158. package/components/primitives/Badge/Badge.tsx +49 -0
  159. package/components/primitives/Badge/index.ts +2 -0
  160. package/components/primitives/Button/Button.stories.tsx +445 -0
  161. package/components/primitives/Button/Button.tsx +89 -0
  162. package/components/primitives/Button/index.ts +7 -0
  163. package/components/primitives/Card/Card.stories.tsx +831 -0
  164. package/components/primitives/Card/Card.tsx +242 -0
  165. package/components/primitives/Card/index.ts +30 -0
  166. package/components/primitives/Carousel/Carousel.stories.tsx +32 -0
  167. package/components/primitives/Carousel/Carousel.tsx +63 -0
  168. package/components/primitives/Carousel/index.ts +13 -0
  169. package/components/primitives/Chart/Chart.stories.tsx +346 -0
  170. package/components/primitives/Chart/Chart.tsx +117 -0
  171. package/components/primitives/Chart/index.ts +20 -0
  172. package/components/primitives/Checkbox/Checkbox.stories.tsx +87 -0
  173. package/components/primitives/Checkbox/Checkbox.tsx +38 -0
  174. package/components/primitives/Checkbox/index.ts +2 -0
  175. package/components/primitives/Collapsible/Collapsible.stories.tsx +38 -0
  176. package/components/primitives/Collapsible/Collapsible.tsx +39 -0
  177. package/components/primitives/Collapsible/index.ts +8 -0
  178. package/components/primitives/Command/Command.stories.tsx +150 -0
  179. package/components/primitives/Command/Command.tsx +147 -0
  180. package/components/primitives/Command/index.ts +20 -0
  181. package/components/primitives/Dialog/Dialog.stories.tsx +390 -0
  182. package/components/primitives/Dialog/Dialog.tsx +140 -0
  183. package/components/primitives/Dialog/index.ts +22 -0
  184. package/components/primitives/Drawer/Drawer.stories.tsx +327 -0
  185. package/components/primitives/Drawer/Drawer.tsx +208 -0
  186. package/components/primitives/Drawer/index.ts +27 -0
  187. package/components/primitives/DropdownMenu/DropdownMenu.stories.tsx +150 -0
  188. package/components/primitives/DropdownMenu/DropdownMenu.tsx +73 -0
  189. package/components/primitives/DropdownMenu/index.ts +1 -0
  190. package/components/primitives/HoverCard/HoverCard.stories.tsx +26 -0
  191. package/components/primitives/HoverCard/HoverCard.tsx +39 -0
  192. package/components/primitives/HoverCard/index.ts +8 -0
  193. package/components/primitives/Icon/Icon.stories.tsx +281 -0
  194. package/components/primitives/Icon/Icon.tsx +87 -0
  195. package/components/primitives/Icon/index.ts +8 -0
  196. package/components/primitives/Input/Input.stories.tsx +370 -0
  197. package/components/primitives/Input/Input.tsx +88 -0
  198. package/components/primitives/Input/index.ts +7 -0
  199. package/components/primitives/InputGroup/InputGroup.stories.tsx +40 -0
  200. package/components/primitives/InputGroup/InputGroup.tsx +72 -0
  201. package/components/primitives/InputGroup/index.ts +14 -0
  202. package/components/primitives/Label/Label.stories.tsx +227 -0
  203. package/components/primitives/Label/Label.tsx +53 -0
  204. package/components/primitives/Label/index.ts +7 -0
  205. package/components/primitives/Popover/Popover.stories.tsx +42 -0
  206. package/components/primitives/Popover/Popover.tsx +107 -0
  207. package/components/primitives/Popover/index.ts +2 -0
  208. package/components/primitives/Progress/Progress.stories.tsx +340 -0
  209. package/components/primitives/Progress/Progress.tsx +31 -0
  210. package/components/primitives/Progress/index.ts +1 -0
  211. package/components/primitives/ScrollArea/ScrollArea.stories.tsx +26 -0
  212. package/components/primitives/ScrollArea/ScrollArea.tsx +28 -0
  213. package/components/primitives/ScrollArea/index.ts +6 -0
  214. package/components/primitives/Select/Select.stories.tsx +288 -0
  215. package/components/primitives/Select/Select.tsx +162 -0
  216. package/components/primitives/Select/index.ts +22 -0
  217. package/components/primitives/Separator/Separator.stories.tsx +264 -0
  218. package/components/primitives/Separator/Separator.tsx +48 -0
  219. package/components/primitives/Separator/index.ts +7 -0
  220. package/components/primitives/Sidebar/Sidebar.stories.tsx +358 -0
  221. package/components/primitives/Sidebar/Sidebar.tsx +317 -0
  222. package/components/primitives/Sidebar/index.ts +41 -0
  223. package/components/primitives/Table/Table.stories.tsx +389 -0
  224. package/components/primitives/Table/Table.tsx +191 -0
  225. package/components/primitives/Table/index.ts +26 -0
  226. package/components/primitives/Tabs/Tabs.stories.tsx +129 -0
  227. package/components/primitives/Tabs/Tabs.tsx +70 -0
  228. package/components/primitives/Tabs/index.ts +13 -0
  229. package/components/primitives/Textarea/Textarea.stories.tsx +358 -0
  230. package/components/primitives/Textarea/Textarea.tsx +91 -0
  231. package/components/primitives/Textarea/index.ts +7 -0
  232. package/components/primitives/ToggleGroup/ToggleGroup.stories.tsx +87 -0
  233. package/components/primitives/ToggleGroup/ToggleGroup.tsx +52 -0
  234. package/components/primitives/ToggleGroup/index.ts +6 -0
  235. package/components/primitives/Tooltip/Tooltip.stories.tsx +336 -0
  236. package/components/primitives/Tooltip/Tooltip.tsx +78 -0
  237. package/components/primitives/Tooltip/index.ts +10 -0
  238. package/components/primitives/index.ts +34 -0
  239. package/components/ui/accordion.tsx +66 -0
  240. package/components/ui/alert-dialog.tsx +157 -0
  241. package/components/ui/alert.tsx +66 -0
  242. package/components/ui/avatar.tsx +53 -0
  243. package/components/ui/badge.tsx +46 -0
  244. package/components/ui/button.tsx +60 -0
  245. package/components/ui/card.tsx +117 -0
  246. package/components/ui/carousel.tsx +241 -0
  247. package/components/ui/chart.tsx +334 -0
  248. package/components/ui/checkbox.tsx +32 -0
  249. package/components/ui/collapsible.tsx +33 -0
  250. package/components/ui/command.tsx +184 -0
  251. package/components/ui/dialog.tsx +143 -0
  252. package/components/ui/drawer.tsx +118 -0
  253. package/components/ui/dropdown-menu.tsx +257 -0
  254. package/components/ui/hover-card.tsx +44 -0
  255. package/components/ui/input-group.tsx +170 -0
  256. package/components/ui/input.tsx +48 -0
  257. package/components/ui/label.tsx +26 -0
  258. package/components/ui/popover.tsx +33 -0
  259. package/components/ui/progress.tsx +31 -0
  260. package/components/ui/scroll-area.tsx +58 -0
  261. package/components/ui/select.tsx +187 -0
  262. package/components/ui/separator.tsx +31 -0
  263. package/components/ui/sidebar.tsx +577 -0
  264. package/components/ui/table.tsx +120 -0
  265. package/components/ui/tabs.tsx +66 -0
  266. package/components/ui/textarea.tsx +46 -0
  267. package/components/ui/toggle-group.tsx +83 -0
  268. package/components/ui/toggle.tsx +47 -0
  269. package/components/ui/tooltip.tsx +61 -0
  270. package/dist/index.cjs +7389 -0
  271. package/dist/index.cjs.map +1 -0
  272. package/dist/index.css +75 -0
  273. package/dist/index.css.map +1 -0
  274. package/dist/index.js +7160 -0
  275. package/dist/index.js.map +1 -0
  276. package/hooks/useAIDocReviewer.d.ts +0 -0
  277. package/lib/utils.ts +6 -0
  278. package/package.json +140 -0
  279. package/tokens/color/base.json +14 -0
  280. package/tokens/color/dark.json +40 -0
  281. package/tokens/color/green.json +21 -0
  282. package/tokens/color/light.json +52 -0
  283. package/tokens/color/neutral.json +20 -0
  284. package/tokens/color/violet.json +21 -0
  285. package/tokens/spacing.json +22 -0
  286. package/utils/ai-editor/format-date.ts +41 -0
  287. package/utils/ai-editor/index.ts +22 -0
  288. package/utils/ai-editor/type-guards.ts +72 -0
  289. package/utils/ai-editor/validation.ts +130 -0
  290. package/utils/editor-annotations.ts +122 -0
@@ -0,0 +1,274 @@
1
+ "use client";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import {
5
+ Collapsible,
6
+ CollapsibleContent,
7
+ CollapsibleTrigger,
8
+ } from "@/components/ui/collapsible";
9
+ import { ScrollArea } from "@/components/ui/scroll-area";
10
+ import { cn } from "@/lib/utils";
11
+ import { ChevronDownIcon, PaperclipIcon } from "lucide-react";
12
+ import type { ComponentProps } from "react";
13
+
14
+ export type QueueMessagePart = {
15
+ type: string;
16
+ text?: string;
17
+ url?: string;
18
+ filename?: string;
19
+ mediaType?: string;
20
+ };
21
+
22
+ export type QueueMessage = {
23
+ id: string;
24
+ parts: QueueMessagePart[];
25
+ };
26
+
27
+ export type QueueTodo = {
28
+ id: string;
29
+ title: string;
30
+ description?: string;
31
+ status?: "pending" | "completed";
32
+ };
33
+
34
+ export type QueueItemProps = ComponentProps<"li">;
35
+
36
+ export const QueueItem = ({ className, ...props }: QueueItemProps) => (
37
+ <li
38
+ className={cn(
39
+ "group flex flex-col gap-1 rounded-md px-3 py-1 text-sm transition-colors hover:bg-muted",
40
+ className
41
+ )}
42
+ {...props}
43
+ />
44
+ );
45
+
46
+ export type QueueItemIndicatorProps = ComponentProps<"span"> & {
47
+ completed?: boolean;
48
+ };
49
+
50
+ export const QueueItemIndicator = ({
51
+ completed = false,
52
+ className,
53
+ ...props
54
+ }: QueueItemIndicatorProps) => (
55
+ <span
56
+ className={cn(
57
+ "mt-0.5 inline-block size-2.5 rounded-full border",
58
+ completed
59
+ ? "border-muted-foreground/20 bg-muted-foreground/10"
60
+ : "border-muted-foreground/50",
61
+ className
62
+ )}
63
+ {...props}
64
+ />
65
+ );
66
+
67
+ export type QueueItemContentProps = ComponentProps<"span"> & {
68
+ completed?: boolean;
69
+ };
70
+
71
+ export const QueueItemContent = ({
72
+ completed = false,
73
+ className,
74
+ ...props
75
+ }: QueueItemContentProps) => (
76
+ <span
77
+ className={cn(
78
+ "line-clamp-1 grow wrap-break-word",
79
+ completed
80
+ ? "text-muted-foreground/50 line-through"
81
+ : "text-muted-foreground",
82
+ className
83
+ )}
84
+ {...props}
85
+ />
86
+ );
87
+
88
+ export type QueueItemDescriptionProps = ComponentProps<"div"> & {
89
+ completed?: boolean;
90
+ };
91
+
92
+ export const QueueItemDescription = ({
93
+ completed = false,
94
+ className,
95
+ ...props
96
+ }: QueueItemDescriptionProps) => (
97
+ <div
98
+ className={cn(
99
+ "ml-6 text-xs",
100
+ completed
101
+ ? "text-muted-foreground/40 line-through"
102
+ : "text-muted-foreground",
103
+ className
104
+ )}
105
+ {...props}
106
+ />
107
+ );
108
+
109
+ export type QueueItemActionsProps = ComponentProps<"div">;
110
+
111
+ export const QueueItemActions = ({
112
+ className,
113
+ ...props
114
+ }: QueueItemActionsProps) => (
115
+ <div className={cn("flex gap-1", className)} {...props} />
116
+ );
117
+
118
+ export type QueueItemActionProps = Omit<
119
+ ComponentProps<typeof Button>,
120
+ "variant" | "size"
121
+ >;
122
+
123
+ export const QueueItemAction = ({
124
+ className,
125
+ ...props
126
+ }: QueueItemActionProps) => (
127
+ <Button
128
+ className={cn(
129
+ "size-auto rounded p-1 text-muted-foreground opacity-0 transition-opacity hover:bg-muted-foreground/10 hover:text-foreground group-hover:opacity-100",
130
+ className
131
+ )}
132
+ size="icon"
133
+ type="button"
134
+ variant="ghost"
135
+ {...props}
136
+ />
137
+ );
138
+
139
+ export type QueueItemAttachmentProps = ComponentProps<"div">;
140
+
141
+ export const QueueItemAttachment = ({
142
+ className,
143
+ ...props
144
+ }: QueueItemAttachmentProps) => (
145
+ <div className={cn("mt-1 flex flex-wrap gap-2", className)} {...props} />
146
+ );
147
+
148
+ export type QueueItemImageProps = ComponentProps<"img">;
149
+
150
+ export const QueueItemImage = ({
151
+ className,
152
+ ...props
153
+ }: QueueItemImageProps) => (
154
+ <img
155
+ alt=""
156
+ className={cn("h-8 w-8 rounded border object-cover", className)}
157
+ height={32}
158
+ width={32}
159
+ {...props}
160
+ />
161
+ );
162
+
163
+ export type QueueItemFileProps = ComponentProps<"span">;
164
+
165
+ export const QueueItemFile = ({
166
+ children,
167
+ className,
168
+ ...props
169
+ }: QueueItemFileProps) => (
170
+ <span
171
+ className={cn(
172
+ "flex items-center gap-1 rounded border bg-muted px-2 py-1 text-xs",
173
+ className
174
+ )}
175
+ {...props}
176
+ >
177
+ <PaperclipIcon size={12} />
178
+ <span className="max-w-[100px] truncate">{children}</span>
179
+ </span>
180
+ );
181
+
182
+ export type QueueListProps = ComponentProps<typeof ScrollArea>;
183
+
184
+ export const QueueList = ({
185
+ children,
186
+ className,
187
+ ...props
188
+ }: QueueListProps) => (
189
+ <ScrollArea className={cn("-mb-1 mt-2", className)} {...props}>
190
+ <div className="max-h-40 pr-4">
191
+ <ul>{children}</ul>
192
+ </div>
193
+ </ScrollArea>
194
+ );
195
+
196
+ // QueueSection - collapsible section container
197
+ export type QueueSectionProps = ComponentProps<typeof Collapsible>;
198
+
199
+ export const QueueSection = ({
200
+ className,
201
+ defaultOpen = true,
202
+ ...props
203
+ }: QueueSectionProps) => (
204
+ <Collapsible className={cn(className)} defaultOpen={defaultOpen} {...props} />
205
+ );
206
+
207
+ // QueueSectionTrigger - section header/trigger
208
+ export type QueueSectionTriggerProps = ComponentProps<"button">;
209
+
210
+ export const QueueSectionTrigger = ({
211
+ children,
212
+ className,
213
+ ...props
214
+ }: QueueSectionTriggerProps) => (
215
+ <CollapsibleTrigger asChild>
216
+ <button
217
+ className={cn(
218
+ "group flex w-full items-center justify-between rounded-md bg-muted/40 px-3 py-2 text-left font-medium text-muted-foreground text-sm transition-colors hover:bg-muted",
219
+ className
220
+ )}
221
+ type="button"
222
+ {...props}
223
+ >
224
+ {children}
225
+ </button>
226
+ </CollapsibleTrigger>
227
+ );
228
+
229
+ // QueueSectionLabel - label content with icon and count
230
+ export type QueueSectionLabelProps = ComponentProps<"span"> & {
231
+ count?: number;
232
+ label: string;
233
+ icon?: React.ReactNode;
234
+ };
235
+
236
+ export const QueueSectionLabel = ({
237
+ count,
238
+ label,
239
+ icon,
240
+ className,
241
+ ...props
242
+ }: QueueSectionLabelProps) => (
243
+ <span className={cn("flex items-center gap-2", className)} {...props}>
244
+ <ChevronDownIcon className="group-data-[state=closed]:-rotate-90 size-4 transition-transform" />
245
+ {icon}
246
+ <span>
247
+ {count} {label}
248
+ </span>
249
+ </span>
250
+ );
251
+
252
+ // QueueSectionContent - collapsible content area
253
+ export type QueueSectionContentProps = ComponentProps<
254
+ typeof CollapsibleContent
255
+ >;
256
+
257
+ export const QueueSectionContent = ({
258
+ className,
259
+ ...props
260
+ }: QueueSectionContentProps) => (
261
+ <CollapsibleContent className={cn(className)} {...props} />
262
+ );
263
+
264
+ export type QueueProps = ComponentProps<"div">;
265
+
266
+ export const Queue = ({ className, ...props }: QueueProps) => (
267
+ <div
268
+ className={cn(
269
+ "flex flex-col gap-2 rounded-xl border border-border bg-background px-3 pt-2 pb-2 shadow-xs",
270
+ className
271
+ )}
272
+ {...props}
273
+ />
274
+ );
@@ -0,0 +1,178 @@
1
+ "use client";
2
+
3
+ import { useControllableState } from "@radix-ui/react-use-controllable-state";
4
+ import {
5
+ Collapsible,
6
+ CollapsibleContent,
7
+ CollapsibleTrigger,
8
+ } from "@/components/ui/collapsible";
9
+ import { cn } from "@/lib/utils";
10
+ import { BrainIcon, ChevronDownIcon } from "lucide-react";
11
+ import type { ComponentProps } from "react";
12
+ import { createContext, memo, useContext, useEffect, useState } from "react";
13
+ import { Response } from "./response";
14
+ import { Shimmer } from "./shimmer";
15
+
16
+ type ReasoningContextValue = {
17
+ isStreaming: boolean;
18
+ isOpen: boolean;
19
+ setIsOpen: (open: boolean) => void;
20
+ duration: number;
21
+ };
22
+
23
+ const ReasoningContext = createContext<ReasoningContextValue | null>(null);
24
+
25
+ const useReasoning = () => {
26
+ const context = useContext(ReasoningContext);
27
+ if (!context) {
28
+ throw new Error("Reasoning components must be used within Reasoning");
29
+ }
30
+ return context;
31
+ };
32
+
33
+ export type ReasoningProps = ComponentProps<typeof Collapsible> & {
34
+ isStreaming?: boolean;
35
+ open?: boolean;
36
+ defaultOpen?: boolean;
37
+ onOpenChange?: (open: boolean) => void;
38
+ duration?: number;
39
+ };
40
+
41
+ const AUTO_CLOSE_DELAY = 1000;
42
+ const MS_IN_S = 1000;
43
+
44
+ export const Reasoning = memo(
45
+ ({
46
+ className,
47
+ isStreaming = false,
48
+ open,
49
+ defaultOpen = true,
50
+ onOpenChange,
51
+ duration: durationProp,
52
+ children,
53
+ ...props
54
+ }: ReasoningProps) => {
55
+ const [isOpen, setIsOpen] = useControllableState({
56
+ prop: open,
57
+ defaultProp: defaultOpen,
58
+ onChange: onOpenChange,
59
+ });
60
+ const [duration, setDuration] = useControllableState({
61
+ prop: durationProp,
62
+ defaultProp: 0,
63
+ });
64
+
65
+ const [hasAutoClosed, setHasAutoClosed] = useState(false);
66
+ const [startTime, setStartTime] = useState<number | null>(null);
67
+
68
+ // Track duration when streaming starts and ends
69
+ useEffect(() => {
70
+ if (isStreaming) {
71
+ if (startTime === null) {
72
+ setStartTime(Date.now());
73
+ }
74
+ } else if (startTime !== null) {
75
+ setDuration(Math.ceil((Date.now() - startTime) / MS_IN_S));
76
+ setStartTime(null);
77
+ }
78
+ }, [isStreaming, startTime, setDuration]);
79
+
80
+ // Auto-open when streaming starts, auto-close when streaming ends (once only)
81
+ useEffect(() => {
82
+ if (defaultOpen && !isStreaming && isOpen && !hasAutoClosed) {
83
+ // Add a small delay before closing to allow user to see the content
84
+ const timer = setTimeout(() => {
85
+ setIsOpen(false);
86
+ setHasAutoClosed(true);
87
+ }, AUTO_CLOSE_DELAY);
88
+
89
+ return () => clearTimeout(timer);
90
+ }
91
+ }, [isStreaming, isOpen, defaultOpen, setIsOpen, hasAutoClosed]);
92
+
93
+ const handleOpenChange = (newOpen: boolean) => {
94
+ setIsOpen(newOpen);
95
+ };
96
+
97
+ return (
98
+ <ReasoningContext.Provider
99
+ value={{ isStreaming, isOpen, setIsOpen, duration }}
100
+ >
101
+ <Collapsible
102
+ className={cn("not-prose mb-4", className)}
103
+ onOpenChange={handleOpenChange}
104
+ open={isOpen}
105
+ {...props}
106
+ >
107
+ {children}
108
+ </Collapsible>
109
+ </ReasoningContext.Provider>
110
+ );
111
+ }
112
+ );
113
+
114
+ export type ReasoningTriggerProps = ComponentProps<typeof CollapsibleTrigger>;
115
+
116
+ const getThinkingMessage = (isStreaming: boolean, duration?: number) => {
117
+ if (isStreaming || duration === 0) {
118
+ return <Shimmer duration={1}>Thinking...</Shimmer>;
119
+ }
120
+ if (duration === undefined) {
121
+ return <p>Thought for a few seconds</p>;
122
+ }
123
+ return <p>Thought for {duration} seconds</p>;
124
+ };
125
+
126
+ export const ReasoningTrigger = memo(
127
+ ({ className, children, ...props }: ReasoningTriggerProps) => {
128
+ const { isStreaming, isOpen, duration } = useReasoning();
129
+
130
+ return (
131
+ <CollapsibleTrigger
132
+ className={cn(
133
+ "flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground",
134
+ className
135
+ )}
136
+ {...props}
137
+ >
138
+ {children ?? (
139
+ <>
140
+ <BrainIcon className="size-4" />
141
+ {getThinkingMessage(isStreaming, duration)}
142
+ <ChevronDownIcon
143
+ className={cn(
144
+ "size-4 transition-transform",
145
+ isOpen ? "rotate-180" : "rotate-0"
146
+ )}
147
+ />
148
+ </>
149
+ )}
150
+ </CollapsibleTrigger>
151
+ );
152
+ }
153
+ );
154
+
155
+ export type ReasoningContentProps = ComponentProps<
156
+ typeof CollapsibleContent
157
+ > & {
158
+ children: string;
159
+ };
160
+
161
+ export const ReasoningContent = memo(
162
+ ({ className, children, ...props }: ReasoningContentProps) => (
163
+ <CollapsibleContent
164
+ className={cn(
165
+ "mt-4 text-sm",
166
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
167
+ className
168
+ )}
169
+ {...props}
170
+ >
171
+ <Response className="grid gap-2">{children}</Response>
172
+ </CollapsibleContent>
173
+ )
174
+ );
175
+
176
+ Reasoning.displayName = "Reasoning";
177
+ ReasoningTrigger.displayName = "ReasoningTrigger";
178
+ ReasoningContent.displayName = "ReasoningContent";
@@ -0,0 +1,22 @@
1
+ "use client";
2
+
3
+ import { cn } from "@/lib/utils";
4
+ import { type ComponentProps, memo } from "react";
5
+ import { Streamdown } from "streamdown";
6
+
7
+ type ResponseProps = ComponentProps<typeof Streamdown>;
8
+
9
+ export const Response = memo(
10
+ ({ className, ...props }: ResponseProps) => (
11
+ <Streamdown
12
+ className={cn(
13
+ "size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
14
+ className
15
+ )}
16
+ {...props}
17
+ />
18
+ ),
19
+ (prevProps, nextProps) => prevProps.children === nextProps.children
20
+ );
21
+
22
+ Response.displayName = "Response";
@@ -0,0 +1,64 @@
1
+ "use client";
2
+
3
+ import { cn } from "@/lib/utils";
4
+ import { motion } from "motion/react";
5
+ import {
6
+ type CSSProperties,
7
+ type ElementType,
8
+ type JSX,
9
+ memo,
10
+ useMemo,
11
+ } from "react";
12
+
13
+ export type TextShimmerProps = {
14
+ children: string;
15
+ as?: ElementType;
16
+ className?: string;
17
+ duration?: number;
18
+ spread?: number;
19
+ };
20
+
21
+ const ShimmerComponent = ({
22
+ children,
23
+ as: Component = "p",
24
+ className,
25
+ duration = 2,
26
+ spread = 2,
27
+ }: TextShimmerProps) => {
28
+ const MotionComponent = motion.create(
29
+ Component as keyof JSX.IntrinsicElements
30
+ );
31
+
32
+ const dynamicSpread = useMemo(
33
+ () => (children?.length ?? 0) * spread,
34
+ [children, spread]
35
+ );
36
+
37
+ return (
38
+ <MotionComponent
39
+ animate={{ backgroundPosition: "0% center" }}
40
+ className={cn(
41
+ "relative inline-block bg-size-[250%_100%,auto] bg-clip-text text-transparent",
42
+ "[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]",
43
+ className
44
+ )}
45
+ initial={{ backgroundPosition: "100% center" }}
46
+ style={
47
+ {
48
+ "--spread": `${dynamicSpread}px`,
49
+ backgroundImage:
50
+ "var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))",
51
+ } as CSSProperties
52
+ }
53
+ transition={{
54
+ repeat: Number.POSITIVE_INFINITY,
55
+ duration,
56
+ ease: "linear",
57
+ }}
58
+ >
59
+ {children}
60
+ </MotionComponent>
61
+ );
62
+ };
63
+
64
+ export const Shimmer = memo(ShimmerComponent);
@@ -0,0 +1,77 @@
1
+ "use client";
2
+
3
+ import {
4
+ Collapsible,
5
+ CollapsibleContent,
6
+ CollapsibleTrigger,
7
+ } from "@/components/ui/collapsible";
8
+ import { cn } from "@/lib/utils";
9
+ import { BookIcon, ChevronDownIcon } from "lucide-react";
10
+ import type { ComponentProps } from "react";
11
+
12
+ export type SourcesProps = ComponentProps<"div">;
13
+
14
+ export const Sources = ({ className, ...props }: SourcesProps) => (
15
+ <Collapsible
16
+ className={cn("not-prose mb-4 text-primary text-xs", className)}
17
+ {...props}
18
+ />
19
+ );
20
+
21
+ export type SourcesTriggerProps = ComponentProps<typeof CollapsibleTrigger> & {
22
+ count: number;
23
+ };
24
+
25
+ export const SourcesTrigger = ({
26
+ className,
27
+ count,
28
+ children,
29
+ ...props
30
+ }: SourcesTriggerProps) => (
31
+ <CollapsibleTrigger
32
+ className={cn("flex items-center gap-2", className)}
33
+ {...props}
34
+ >
35
+ {children ?? (
36
+ <>
37
+ <p className="font-medium">Used {count} sources</p>
38
+ <ChevronDownIcon className="h-4 w-4" />
39
+ </>
40
+ )}
41
+ </CollapsibleTrigger>
42
+ );
43
+
44
+ export type SourcesContentProps = ComponentProps<typeof CollapsibleContent>;
45
+
46
+ export const SourcesContent = ({
47
+ className,
48
+ ...props
49
+ }: SourcesContentProps) => (
50
+ <CollapsibleContent
51
+ className={cn(
52
+ "mt-3 flex w-fit flex-col gap-2",
53
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
54
+ className
55
+ )}
56
+ {...props}
57
+ />
58
+ );
59
+
60
+ export type SourceProps = ComponentProps<"a">;
61
+
62
+ export const Source = ({ href, title, children, ...props }: SourceProps) => (
63
+ <a
64
+ className="flex items-center gap-2"
65
+ href={href}
66
+ rel="noreferrer"
67
+ target="_blank"
68
+ {...props}
69
+ >
70
+ {children ?? (
71
+ <>
72
+ <BookIcon className="h-4 w-4" />
73
+ <span className="block font-medium">{title}</span>
74
+ </>
75
+ )}
76
+ </a>
77
+ );
@@ -0,0 +1,56 @@
1
+ "use client";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import {
5
+ ScrollArea,
6
+ ScrollBar,
7
+ } from "@/components/ui/scroll-area";
8
+ import { cn } from "@/lib/utils";
9
+ import type { ComponentProps } from "react";
10
+
11
+ export type SuggestionsProps = ComponentProps<typeof ScrollArea>;
12
+
13
+ export const Suggestions = ({
14
+ className,
15
+ children,
16
+ ...props
17
+ }: SuggestionsProps) => (
18
+ <ScrollArea className="w-full overflow-x-auto whitespace-nowrap" {...props}>
19
+ <div className={cn("flex w-max flex-nowrap items-center gap-2", className)}>
20
+ {children}
21
+ </div>
22
+ <ScrollBar className="hidden" orientation="horizontal" />
23
+ </ScrollArea>
24
+ );
25
+
26
+ export type SuggestionProps = Omit<ComponentProps<typeof Button>, "onClick"> & {
27
+ suggestion: string;
28
+ onClick?: (suggestion: string) => void;
29
+ };
30
+
31
+ export const Suggestion = ({
32
+ suggestion,
33
+ onClick,
34
+ className,
35
+ variant = "outline",
36
+ size = "sm",
37
+ children,
38
+ ...props
39
+ }: SuggestionProps) => {
40
+ const handleClick = () => {
41
+ onClick?.(suggestion);
42
+ };
43
+
44
+ return (
45
+ <Button
46
+ className={cn("cursor-pointer rounded-full px-4", className)}
47
+ onClick={handleClick}
48
+ size={size}
49
+ type="button"
50
+ variant={variant}
51
+ {...props}
52
+ >
53
+ {children || suggestion}
54
+ </Button>
55
+ );
56
+ };