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,87 @@
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 { ChevronDownIcon, SearchIcon } from "lucide-react";
10
+ import type { ComponentProps } from "react";
11
+
12
+ export type TaskItemFileProps = ComponentProps<"div">;
13
+
14
+ export const TaskItemFile = ({
15
+ children,
16
+ className,
17
+ ...props
18
+ }: TaskItemFileProps) => (
19
+ <div
20
+ className={cn(
21
+ "inline-flex items-center gap-1 rounded-md border bg-secondary px-1.5 py-0.5 text-foreground text-xs",
22
+ className
23
+ )}
24
+ {...props}
25
+ >
26
+ {children}
27
+ </div>
28
+ );
29
+
30
+ export type TaskItemProps = ComponentProps<"div">;
31
+
32
+ export const TaskItem = ({ children, className, ...props }: TaskItemProps) => (
33
+ <div className={cn("text-muted-foreground text-sm", className)} {...props}>
34
+ {children}
35
+ </div>
36
+ );
37
+
38
+ export type TaskProps = ComponentProps<typeof Collapsible>;
39
+
40
+ export const Task = ({
41
+ defaultOpen = true,
42
+ className,
43
+ ...props
44
+ }: TaskProps) => (
45
+ <Collapsible className={cn(className)} defaultOpen={defaultOpen} {...props} />
46
+ );
47
+
48
+ export type TaskTriggerProps = ComponentProps<typeof CollapsibleTrigger> & {
49
+ title: string;
50
+ };
51
+
52
+ export const TaskTrigger = ({
53
+ children,
54
+ className,
55
+ title,
56
+ ...props
57
+ }: TaskTriggerProps) => (
58
+ <CollapsibleTrigger asChild className={cn("group", className)} {...props}>
59
+ {children ?? (
60
+ <div className="flex w-full cursor-pointer items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground">
61
+ <SearchIcon className="size-4" />
62
+ <p className="text-sm">{title}</p>
63
+ <ChevronDownIcon className="size-4 transition-transform group-data-[state=open]:rotate-180" />
64
+ </div>
65
+ )}
66
+ </CollapsibleTrigger>
67
+ );
68
+
69
+ export type TaskContentProps = ComponentProps<typeof CollapsibleContent>;
70
+
71
+ export const TaskContent = ({
72
+ children,
73
+ className,
74
+ ...props
75
+ }: TaskContentProps) => (
76
+ <CollapsibleContent
77
+ className={cn(
78
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
79
+ className
80
+ )}
81
+ {...props}
82
+ >
83
+ <div className="mt-4 space-y-2 border-muted border-l-2 pl-4">
84
+ {children}
85
+ </div>
86
+ </CollapsibleContent>
87
+ );
@@ -0,0 +1,179 @@
1
+ "use client";
2
+
3
+ import { Badge } from "@/components/ui/badge";
4
+ import {
5
+ Collapsible,
6
+ CollapsibleContent,
7
+ CollapsibleTrigger,
8
+ } from "@/components/ui/collapsible";
9
+ import { cn } from "@/lib/utils";
10
+ // Define our own types since ToolUIPart doesn't exist in current AI SDK
11
+ type ToolUIState =
12
+ | "input-streaming"
13
+ | "input-available"
14
+ | "approval-requested"
15
+ | "approval-responded"
16
+ | "output-denied"
17
+ | "output-available"
18
+ | "output-error";
19
+
20
+ type ToolUIPart = {
21
+ type: `tool-${string}`;
22
+ state: ToolUIState;
23
+ input?: any;
24
+ output?: any;
25
+ errorText?: string;
26
+ };
27
+ import {
28
+ CheckCircleIcon,
29
+ ChevronDownIcon,
30
+ CircleIcon,
31
+ ClockIcon,
32
+ WrenchIcon,
33
+ XCircleIcon,
34
+ } from "lucide-react";
35
+ import type { ComponentProps, ReactNode } from "react";
36
+ import { isValidElement } from "react";
37
+ import { CodeBlock } from "./code-block";
38
+
39
+ export type ToolProps = ComponentProps<typeof Collapsible>;
40
+
41
+ export const Tool = ({ className, ...props }: ToolProps) => (
42
+ <Collapsible
43
+ className={cn("not-prose mb-4 w-full rounded-md border", className)}
44
+ {...props}
45
+ />
46
+ );
47
+
48
+ export type ToolHeaderProps = {
49
+ title?: string;
50
+ type: ToolUIPart["type"];
51
+ state: ToolUIPart["state"];
52
+ className?: string;
53
+ };
54
+
55
+ const getStatusBadge = (status: ToolUIPart["state"]) => {
56
+ const labels: Record<ToolUIPart["state"], string> = {
57
+ "input-streaming": "Pending",
58
+ "input-available": "Running",
59
+ "approval-requested": "Awaiting Approval",
60
+ "approval-responded": "Responded",
61
+ "output-available": "Completed",
62
+ "output-error": "Error",
63
+ "output-denied": "Denied",
64
+ };
65
+
66
+ const icons: Record<ToolUIPart["state"], ReactNode> = {
67
+ "input-streaming": <CircleIcon className="size-4" />,
68
+ "input-available": <ClockIcon className="size-4 animate-pulse" />,
69
+ "approval-requested": <ClockIcon className="size-4 text-yellow-600" />,
70
+ "approval-responded": <CheckCircleIcon className="size-4 text-blue-600" />,
71
+ "output-available": <CheckCircleIcon className="size-4 text-green-600" />,
72
+ "output-error": <XCircleIcon className="size-4 text-red-600" />,
73
+ "output-denied": <XCircleIcon className="size-4 text-orange-600" />,
74
+ };
75
+
76
+ return (
77
+ <Badge className="gap-1.5 rounded-full text-xs" variant="secondary">
78
+ {icons[status]}
79
+ {labels[status]}
80
+ </Badge>
81
+ );
82
+ };
83
+
84
+ export const ToolHeader = ({
85
+ className,
86
+ title,
87
+ type,
88
+ state,
89
+ ...props
90
+ }: ToolHeaderProps) => (
91
+ <CollapsibleTrigger
92
+ className={cn(
93
+ "flex w-full items-center justify-between gap-4 p-3",
94
+ className
95
+ )}
96
+ {...props}
97
+ >
98
+ <div className="flex items-center gap-2">
99
+ <WrenchIcon className="size-4 text-muted-foreground" />
100
+ <span className="font-medium text-sm">
101
+ {title ?? type.split("-").slice(1).join("-")}
102
+ </span>
103
+ {getStatusBadge(state)}
104
+ </div>
105
+ <ChevronDownIcon className="size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" />
106
+ </CollapsibleTrigger>
107
+ );
108
+
109
+ export type ToolContentProps = ComponentProps<typeof CollapsibleContent>;
110
+
111
+ export const ToolContent = ({ className, ...props }: ToolContentProps) => (
112
+ <CollapsibleContent
113
+ className={cn(
114
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
115
+ className
116
+ )}
117
+ {...props}
118
+ />
119
+ );
120
+
121
+ export type ToolInputProps = ComponentProps<"div"> & {
122
+ input: ToolUIPart["input"];
123
+ };
124
+
125
+ export const ToolInput = ({ className, input, ...props }: ToolInputProps) => (
126
+ <div className={cn("space-y-2 overflow-hidden p-4", className)} {...props}>
127
+ <h4 className="font-medium text-muted-foreground text-xs uppercase tracking-wide">
128
+ Parameters
129
+ </h4>
130
+ <div className="rounded-md bg-muted/50">
131
+ <CodeBlock code={JSON.stringify(input, null, 2)} language="json" />
132
+ </div>
133
+ </div>
134
+ );
135
+
136
+ export type ToolOutputProps = ComponentProps<"div"> & {
137
+ output: ToolUIPart["output"];
138
+ errorText: ToolUIPart["errorText"];
139
+ };
140
+
141
+ export const ToolOutput = ({
142
+ className,
143
+ output,
144
+ errorText,
145
+ ...props
146
+ }: ToolOutputProps) => {
147
+ if (!(output || errorText)) {
148
+ return null;
149
+ }
150
+
151
+ let Output = <div>{output as ReactNode}</div>;
152
+
153
+ if (typeof output === "object" && !isValidElement(output)) {
154
+ Output = (
155
+ <CodeBlock code={JSON.stringify(output, null, 2)} language="json" />
156
+ );
157
+ } else if (typeof output === "string") {
158
+ Output = <CodeBlock code={output} language="json" />;
159
+ }
160
+
161
+ return (
162
+ <div className={cn("space-y-2 p-4", className)} {...props}>
163
+ <h4 className="font-medium text-muted-foreground text-xs uppercase tracking-wide">
164
+ {errorText ? "Error" : "Result"}
165
+ </h4>
166
+ <div
167
+ className={cn(
168
+ "overflow-x-auto rounded-md text-xs [&_table]:w-full",
169
+ errorText
170
+ ? "bg-destructive/10 text-destructive"
171
+ : "bg-muted/50 text-foreground"
172
+ )}
173
+ >
174
+ {errorText && <div>{errorText}</div>}
175
+ {Output}
176
+ </div>
177
+ </div>
178
+ );
179
+ };
@@ -0,0 +1,16 @@
1
+ import { cn } from "@/lib/utils";
2
+ import { NodeToolbar, Position } from "@xyflow/react";
3
+ import type { ComponentProps } from "react";
4
+
5
+ type ToolbarProps = ComponentProps<typeof NodeToolbar>;
6
+
7
+ export const Toolbar = ({ className, ...props }: ToolbarProps) => (
8
+ <NodeToolbar
9
+ className={cn(
10
+ "flex items-center gap-1 rounded-sm border bg-background p-1.5",
11
+ className
12
+ )}
13
+ position={Position.Bottom}
14
+ {...props}
15
+ />
16
+ );
@@ -0,0 +1,263 @@
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 { Input } from "@/components/ui/input";
10
+ import {
11
+ Tooltip,
12
+ TooltipContent,
13
+ TooltipProvider,
14
+ TooltipTrigger,
15
+ } from "@/components/ui/tooltip";
16
+ import { cn } from "@/lib/utils";
17
+ import { ChevronDownIcon } from "lucide-react";
18
+ import type { ComponentProps, ReactNode } from "react";
19
+ import { createContext, useContext, useEffect, useState } from "react";
20
+
21
+ export type WebPreviewContextValue = {
22
+ url: string;
23
+ setUrl: (url: string) => void;
24
+ consoleOpen: boolean;
25
+ setConsoleOpen: (open: boolean) => void;
26
+ };
27
+
28
+ const WebPreviewContext = createContext<WebPreviewContextValue | null>(null);
29
+
30
+ const useWebPreview = () => {
31
+ const context = useContext(WebPreviewContext);
32
+ if (!context) {
33
+ throw new Error("WebPreview components must be used within a WebPreview");
34
+ }
35
+ return context;
36
+ };
37
+
38
+ export type WebPreviewProps = ComponentProps<"div"> & {
39
+ defaultUrl?: string;
40
+ onUrlChange?: (url: string) => void;
41
+ };
42
+
43
+ export const WebPreview = ({
44
+ className,
45
+ children,
46
+ defaultUrl = "",
47
+ onUrlChange,
48
+ ...props
49
+ }: WebPreviewProps) => {
50
+ const [url, setUrl] = useState(defaultUrl);
51
+ const [consoleOpen, setConsoleOpen] = useState(false);
52
+
53
+ const handleUrlChange = (newUrl: string) => {
54
+ setUrl(newUrl);
55
+ onUrlChange?.(newUrl);
56
+ };
57
+
58
+ const contextValue: WebPreviewContextValue = {
59
+ url,
60
+ setUrl: handleUrlChange,
61
+ consoleOpen,
62
+ setConsoleOpen,
63
+ };
64
+
65
+ return (
66
+ <WebPreviewContext.Provider value={contextValue}>
67
+ <div
68
+ className={cn(
69
+ "flex size-full flex-col rounded-lg border bg-card",
70
+ className
71
+ )}
72
+ {...props}
73
+ >
74
+ {children}
75
+ </div>
76
+ </WebPreviewContext.Provider>
77
+ );
78
+ };
79
+
80
+ export type WebPreviewNavigationProps = ComponentProps<"div">;
81
+
82
+ export const WebPreviewNavigation = ({
83
+ className,
84
+ children,
85
+ ...props
86
+ }: WebPreviewNavigationProps) => (
87
+ <div
88
+ className={cn("flex items-center gap-1 border-b p-2", className)}
89
+ {...props}
90
+ >
91
+ {children}
92
+ </div>
93
+ );
94
+
95
+ export type WebPreviewNavigationButtonProps = ComponentProps<typeof Button> & {
96
+ tooltip?: string;
97
+ };
98
+
99
+ export const WebPreviewNavigationButton = ({
100
+ onClick,
101
+ disabled,
102
+ tooltip,
103
+ children,
104
+ ...props
105
+ }: WebPreviewNavigationButtonProps) => (
106
+ <TooltipProvider>
107
+ <Tooltip>
108
+ <TooltipTrigger asChild>
109
+ <Button
110
+ className="h-8 w-8 p-0 hover:text-foreground"
111
+ disabled={disabled}
112
+ onClick={onClick}
113
+ size="sm"
114
+ variant="ghost"
115
+ {...props}
116
+ >
117
+ {children}
118
+ </Button>
119
+ </TooltipTrigger>
120
+ <TooltipContent>
121
+ <p>{tooltip}</p>
122
+ </TooltipContent>
123
+ </Tooltip>
124
+ </TooltipProvider>
125
+ );
126
+
127
+ export type WebPreviewUrlProps = ComponentProps<typeof Input>;
128
+
129
+ export const WebPreviewUrl = ({
130
+ value,
131
+ onChange,
132
+ onKeyDown,
133
+ ...props
134
+ }: WebPreviewUrlProps) => {
135
+ const { url, setUrl } = useWebPreview();
136
+ const [inputValue, setInputValue] = useState(url);
137
+
138
+ // Sync input value with context URL when it changes externally
139
+ useEffect(() => {
140
+ setInputValue(url);
141
+ }, [url]);
142
+
143
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
144
+ setInputValue(event.target.value);
145
+ onChange?.(event);
146
+ };
147
+
148
+ const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
149
+ if (event.key === "Enter") {
150
+ const target = event.target as HTMLInputElement;
151
+ setUrl(target.value);
152
+ }
153
+ onKeyDown?.(event);
154
+ };
155
+
156
+ return (
157
+ <Input
158
+ className="h-8 flex-1 text-sm"
159
+ onChange={onChange ?? handleChange}
160
+ onKeyDown={handleKeyDown}
161
+ placeholder="Enter URL..."
162
+ value={value ?? inputValue}
163
+ {...props}
164
+ />
165
+ );
166
+ };
167
+
168
+ export type WebPreviewBodyProps = ComponentProps<"iframe"> & {
169
+ loading?: ReactNode;
170
+ };
171
+
172
+ export const WebPreviewBody = ({
173
+ className,
174
+ loading,
175
+ src,
176
+ ...props
177
+ }: WebPreviewBodyProps) => {
178
+ const { url } = useWebPreview();
179
+
180
+ return (
181
+ <div className="flex-1">
182
+ <iframe
183
+ className={cn("size-full", className)}
184
+ sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-presentation"
185
+ src={(src ?? url) || undefined}
186
+ title="Preview"
187
+ {...props}
188
+ />
189
+ {loading}
190
+ </div>
191
+ );
192
+ };
193
+
194
+ export type WebPreviewConsoleProps = ComponentProps<"div"> & {
195
+ logs?: Array<{
196
+ level: "log" | "warn" | "error";
197
+ message: string;
198
+ timestamp: Date;
199
+ }>;
200
+ };
201
+
202
+ export const WebPreviewConsole = ({
203
+ className,
204
+ logs = [],
205
+ children,
206
+ ...props
207
+ }: WebPreviewConsoleProps) => {
208
+ const { consoleOpen, setConsoleOpen } = useWebPreview();
209
+
210
+ return (
211
+ <Collapsible
212
+ className={cn("border-t bg-muted/50 font-mono text-sm", className)}
213
+ onOpenChange={setConsoleOpen}
214
+ open={consoleOpen}
215
+ {...props}
216
+ >
217
+ <CollapsibleTrigger asChild>
218
+ <Button
219
+ className="flex w-full items-center justify-between p-4 text-left font-medium hover:bg-muted/50"
220
+ variant="ghost"
221
+ >
222
+ Console
223
+ <ChevronDownIcon
224
+ className={cn(
225
+ "h-4 w-4 transition-transform duration-200",
226
+ consoleOpen && "rotate-180"
227
+ )}
228
+ />
229
+ </Button>
230
+ </CollapsibleTrigger>
231
+ <CollapsibleContent
232
+ className={cn(
233
+ "px-4 pb-4",
234
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in"
235
+ )}
236
+ >
237
+ <div className="max-h-48 space-y-1 overflow-y-auto">
238
+ {logs.length === 0 ? (
239
+ <p className="text-muted-foreground">No console output</p>
240
+ ) : (
241
+ logs.map((log, index) => (
242
+ <div
243
+ className={cn(
244
+ "text-xs",
245
+ log.level === "error" && "text-destructive",
246
+ log.level === "warn" && "text-yellow-600",
247
+ log.level === "log" && "text-foreground"
248
+ )}
249
+ key={`${log.timestamp.getTime()}-${index}`}
250
+ >
251
+ <span className="text-muted-foreground">
252
+ {log.timestamp.toLocaleTimeString()}
253
+ </span>{" "}
254
+ {log.message}
255
+ </div>
256
+ ))
257
+ )}
258
+ {children}
259
+ </div>
260
+ </CollapsibleContent>
261
+ </Collapsible>
262
+ );
263
+ };
@@ -0,0 +1,164 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { AIConversation } from './AIConversation'
3
+
4
+ const meta: Meta<typeof AIConversation> = {
5
+ title: 'Blocks/AIConversation',
6
+ component: AIConversation,
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ },
10
+ } satisfies Meta<typeof AIConversation>
11
+
12
+ export default meta
13
+ type Story = StoryObj<typeof meta>
14
+
15
+ export const Default: Story = {
16
+ args: {
17
+ messages: [
18
+ {
19
+ id: '1',
20
+ type: 'human',
21
+ role: 'user',
22
+ content: 'Compare the achievements of LeBron James and Michael Jordan',
23
+ avatarSrc: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=32&h=32&fit=crop&crop=face',
24
+ avatarName: 'User',
25
+ },
26
+ {
27
+ id: '2',
28
+ type: 'ai',
29
+ role: 'orchestrator',
30
+ content: 'I\'ll help you conduct a comprehensive comparison of LeBron James and Michael Jordan\'s achievements. Let me start by recording your question and creating a plan for this research.',
31
+ avatarSrc: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=32&h=32&fit=crop&crop=face',
32
+ avatarName: 'Coordinator',
33
+ toolCalls: [
34
+ {
35
+ id: 'tool_1',
36
+ name: 'write_file',
37
+ args: { filename: 'research_plan.md', content: 'Research plan for comparing LeBron and Jordan' },
38
+ result: 'File created successfully',
39
+ status: 'completed',
40
+ },
41
+ {
42
+ id: 'tool_2',
43
+ name: 'write_todos',
44
+ args: { todos: ['Gather LeBron stats', 'Gather Jordan stats', 'Compare achievements'] },
45
+ result: 'Todo list created',
46
+ status: 'completed',
47
+ },
48
+ ],
49
+ subAgents: [
50
+ {
51
+ id: 'agent_1',
52
+ name: 'task',
53
+ subAgentName: 'research-agent',
54
+ input: 'Research LeBron James career achievements and statistics. I need comprehensive information including NBA championships, Finals MVP awards, regular season MVP awards, All-Star selections, All-NBA team selections, career statistics (points, rebounds, assists, etc.), notable records for finals, playoff...',
55
+ output: null,
56
+ status: 'active',
57
+ },
58
+ ],
59
+ },
60
+ ],
61
+ },
62
+ }
63
+
64
+ export const MultipleAgents: Story = {
65
+ args: {
66
+ messages: [
67
+ {
68
+ id: '1',
69
+ type: 'human',
70
+ role: 'user',
71
+ content: 'Analyze the performance of our web application',
72
+ avatarSrc: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=32&h=32&fit=crop&crop=face',
73
+ avatarName: 'User',
74
+ },
75
+ {
76
+ id: '2',
77
+ type: 'ai',
78
+ role: 'orchestrator',
79
+ content: 'I\'ll coordinate a comprehensive performance analysis using multiple specialized agents.',
80
+ avatarSrc: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=32&h=32&fit=crop&crop=face',
81
+ avatarName: 'Coordinator',
82
+ toolCalls: [
83
+ {
84
+ id: 'tool_1',
85
+ name: 'analyze_performance',
86
+ args: { url: 'https://example.com', metrics: ['LCP', 'FID', 'CLS'] },
87
+ result: 'Performance analysis completed',
88
+ status: 'completed',
89
+ },
90
+ {
91
+ id: 'tool_2',
92
+ name: 'generate_report',
93
+ args: { format: 'detailed', include_recommendations: true },
94
+ result: null,
95
+ status: 'pending',
96
+ },
97
+ ],
98
+ subAgents: [
99
+ {
100
+ id: 'agent_1',
101
+ name: 'performance-analyzer',
102
+ subAgentName: 'performance-agent',
103
+ input: 'Analyze Core Web Vitals and performance metrics',
104
+ output: 'LCP: 2.1s, FID: 45ms, CLS: 0.12',
105
+ status: 'completed',
106
+ },
107
+ {
108
+ id: 'agent_2',
109
+ name: 'security-scanner',
110
+ subAgentName: 'security-agent',
111
+ input: 'Scan for security vulnerabilities and best practices',
112
+ output: null,
113
+ status: 'active',
114
+ },
115
+ {
116
+ id: 'agent_3',
117
+ name: 'accessibility-checker',
118
+ subAgentName: 'a11y-agent',
119
+ input: 'Check WCAG compliance and accessibility issues',
120
+ output: null,
121
+ status: 'pending',
122
+ },
123
+ ],
124
+ },
125
+ ],
126
+ },
127
+ }
128
+
129
+ export const Empty: Story = {
130
+ args: {
131
+ messages: [],
132
+ },
133
+ }
134
+
135
+ export const UserOnly: Story = {
136
+ args: {
137
+ messages: [
138
+ {
139
+ id: '1',
140
+ type: 'human',
141
+ role: 'user',
142
+ content: 'First user message asking about something',
143
+ avatarSrc: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=32&h=32&fit=crop&crop=face',
144
+ avatarName: 'User',
145
+ },
146
+ {
147
+ id: '2',
148
+ type: 'human',
149
+ role: 'user',
150
+ content: 'Second user message with follow-up question',
151
+ avatarSrc: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=32&h=32&fit=crop&crop=face',
152
+ avatarName: 'User',
153
+ },
154
+ {
155
+ id: '3',
156
+ type: 'human',
157
+ role: 'user',
158
+ content: 'Third user message providing additional context',
159
+ avatarSrc: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=32&h=32&fit=crop&crop=face',
160
+ avatarName: 'User',
161
+ },
162
+ ],
163
+ },
164
+ }