@superblocksteam/vite-plugin-file-sync 2.0.114 → 2.0.115-next.1

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 (355) hide show
  1. package/dist/ai-service/agent/middleware.d.ts.map +1 -1
  2. package/dist/ai-service/agent/middleware.js +19 -0
  3. package/dist/ai-service/agent/middleware.js.map +1 -1
  4. package/dist/ai-service/agent/prompts/api-prompts.d.ts.map +1 -1
  5. package/dist/ai-service/agent/prompts/api-prompts.js +13 -17
  6. package/dist/ai-service/agent/prompts/api-prompts.js.map +1 -1
  7. package/dist/ai-service/agent/prompts/build-base-system-prompt.d.ts.map +1 -1
  8. package/dist/ai-service/agent/prompts/build-base-system-prompt.js +22 -3
  9. package/dist/ai-service/agent/prompts/build-base-system-prompt.js.map +1 -1
  10. package/dist/ai-service/agent/subagents/coding/prompt-builder.d.ts +16 -0
  11. package/dist/ai-service/agent/subagents/coding/prompt-builder.d.ts.map +1 -0
  12. package/dist/ai-service/agent/subagents/coding/prompt-builder.js +30 -0
  13. package/dist/ai-service/agent/subagents/coding/prompt-builder.js.map +1 -0
  14. package/dist/ai-service/agent/subagents/coding/run-coding-subagent.d.ts +29 -0
  15. package/dist/ai-service/agent/subagents/coding/run-coding-subagent.d.ts.map +1 -0
  16. package/dist/ai-service/agent/subagents/coding/run-coding-subagent.js +108 -0
  17. package/dist/ai-service/agent/subagents/coding/run-coding-subagent.js.map +1 -0
  18. package/dist/ai-service/agent/subagents/types.d.ts +9 -1
  19. package/dist/ai-service/agent/subagents/types.d.ts.map +1 -1
  20. package/dist/ai-service/agent/subagents/types.js +8 -0
  21. package/dist/ai-service/agent/subagents/types.js.map +1 -1
  22. package/dist/ai-service/agent/tool-message-utils.d.ts.map +1 -1
  23. package/dist/ai-service/agent/tool-message-utils.js +5 -0
  24. package/dist/ai-service/agent/tool-message-utils.js.map +1 -1
  25. package/dist/ai-service/agent/tools/apis/api-validation-orchestrator.d.ts.map +1 -1
  26. package/dist/ai-service/agent/tools/apis/api-validation-orchestrator.js +2 -1
  27. package/dist/ai-service/agent/tools/apis/api-validation-orchestrator.js.map +1 -1
  28. package/dist/ai-service/agent/tools/apis/get-sdk-api-docs.d.ts +6 -0
  29. package/dist/ai-service/agent/tools/apis/get-sdk-api-docs.d.ts.map +1 -0
  30. package/dist/ai-service/agent/tools/apis/get-sdk-api-docs.js +138 -0
  31. package/dist/ai-service/agent/tools/apis/get-sdk-api-docs.js.map +1 -0
  32. package/dist/ai-service/agent/tools/build-finalize.d.ts.map +1 -1
  33. package/dist/ai-service/agent/tools/build-finalize.js +39 -15
  34. package/dist/ai-service/agent/tools/build-finalize.js.map +1 -1
  35. package/dist/ai-service/agent/tools/build-manage-checklist.d.ts +6 -3
  36. package/dist/ai-service/agent/tools/build-manage-checklist.d.ts.map +1 -1
  37. package/dist/ai-service/agent/tools/build-manage-checklist.js +116 -49
  38. package/dist/ai-service/agent/tools/build-manage-checklist.js.map +1 -1
  39. package/dist/ai-service/agent/tools/index.d.ts +2 -0
  40. package/dist/ai-service/agent/tools/index.d.ts.map +1 -1
  41. package/dist/ai-service/agent/tools/index.js +2 -0
  42. package/dist/ai-service/agent/tools/index.js.map +1 -1
  43. package/dist/ai-service/agent/tools/integrations/execute-request.d.ts +3 -0
  44. package/dist/ai-service/agent/tools/integrations/execute-request.d.ts.map +1 -1
  45. package/dist/ai-service/agent/tools/integrations/execute-request.js +330 -204
  46. package/dist/ai-service/agent/tools/integrations/execute-request.js.map +1 -1
  47. package/dist/ai-service/agent/tools.d.ts.map +1 -1
  48. package/dist/ai-service/agent/tools.js +40 -2
  49. package/dist/ai-service/agent/tools.js.map +1 -1
  50. package/dist/ai-service/agent/tools2/access-control.d.ts +1 -1
  51. package/dist/ai-service/agent/tools2/access-control.d.ts.map +1 -1
  52. package/dist/ai-service/agent/tools2/access-control.js +15 -4
  53. package/dist/ai-service/agent/tools2/access-control.js.map +1 -1
  54. package/dist/ai-service/agent/tools2/registry.d.ts +3 -0
  55. package/dist/ai-service/agent/tools2/registry.d.ts.map +1 -1
  56. package/dist/ai-service/agent/tools2/registry.js +50 -8
  57. package/dist/ai-service/agent/tools2/registry.js.map +1 -1
  58. package/dist/ai-service/agent/tools2/tools/ask-multi-choice.d.ts.map +1 -1
  59. package/dist/ai-service/agent/tools2/tools/ask-multi-choice.js +3 -2
  60. package/dist/ai-service/agent/tools2/tools/ask-multi-choice.js.map +1 -1
  61. package/dist/ai-service/agent/tools2/tools/ask-searchable-dropdown.d.ts.map +1 -1
  62. package/dist/ai-service/agent/tools2/tools/ask-searchable-dropdown.js +2 -1
  63. package/dist/ai-service/agent/tools2/tools/ask-searchable-dropdown.js.map +1 -1
  64. package/dist/ai-service/agent/tools2/tools/deploy-service.d.ts +16 -0
  65. package/dist/ai-service/agent/tools2/tools/deploy-service.d.ts.map +1 -0
  66. package/dist/ai-service/agent/tools2/tools/deploy-service.js +135 -0
  67. package/dist/ai-service/agent/tools2/tools/deploy-service.js.map +1 -0
  68. package/dist/ai-service/agent/tools2/tools/download-attachments.d.ts +33 -0
  69. package/dist/ai-service/agent/tools2/tools/download-attachments.d.ts.map +1 -0
  70. package/dist/ai-service/agent/tools2/tools/download-attachments.js +308 -0
  71. package/dist/ai-service/agent/tools2/tools/download-attachments.js.map +1 -0
  72. package/dist/ai-service/agent/tools2/tools/exit-plan-mode.d.ts.map +1 -1
  73. package/dist/ai-service/agent/tools2/tools/exit-plan-mode.js +8 -4
  74. package/dist/ai-service/agent/tools2/tools/exit-plan-mode.js.map +1 -1
  75. package/dist/ai-service/agent/tools2/tools/git.d.ts +57 -1
  76. package/dist/ai-service/agent/tools2/tools/git.d.ts.map +1 -1
  77. package/dist/ai-service/agent/tools2/tools/git.js +275 -8
  78. package/dist/ai-service/agent/tools2/tools/git.js.map +1 -1
  79. package/dist/ai-service/agent/tools2/tools/index.d.ts +2 -1
  80. package/dist/ai-service/agent/tools2/tools/index.d.ts.map +1 -1
  81. package/dist/ai-service/agent/tools2/tools/index.js +2 -1
  82. package/dist/ai-service/agent/tools2/tools/index.js.map +1 -1
  83. package/dist/ai-service/agent/tools2/tools/list-attachments.d.ts +4 -1
  84. package/dist/ai-service/agent/tools2/tools/list-attachments.d.ts.map +1 -1
  85. package/dist/ai-service/agent/tools2/tools/list-attachments.js +20 -4
  86. package/dist/ai-service/agent/tools2/tools/list-attachments.js.map +1 -1
  87. package/dist/ai-service/agent/tools2/tools/spawn-coding-subagents.d.ts +28 -0
  88. package/dist/ai-service/agent/tools2/tools/spawn-coding-subagents.d.ts.map +1 -0
  89. package/dist/ai-service/agent/tools2/tools/spawn-coding-subagents.js +152 -0
  90. package/dist/ai-service/agent/tools2/tools/spawn-coding-subagents.js.map +1 -0
  91. package/dist/ai-service/agent/tools2/types.d.ts +1 -18
  92. package/dist/ai-service/agent/tools2/types.d.ts.map +1 -1
  93. package/dist/ai-service/agent/tools2/types.js.map +1 -1
  94. package/dist/ai-service/agent/utils.d.ts.map +1 -1
  95. package/dist/ai-service/agent/utils.js +22 -5
  96. package/dist/ai-service/agent/utils.js.map +1 -1
  97. package/dist/ai-service/app-interface/file-system-interface.d.ts +0 -4
  98. package/dist/ai-service/app-interface/file-system-interface.d.ts.map +1 -1
  99. package/dist/ai-service/app-interface/file-system-interface.js +0 -21
  100. package/dist/ai-service/app-interface/file-system-interface.js.map +1 -1
  101. package/dist/ai-service/app-interface/filesystem/virtual-file-system.d.ts +11 -1
  102. package/dist/ai-service/app-interface/filesystem/virtual-file-system.d.ts.map +1 -1
  103. package/dist/ai-service/app-interface/filesystem/virtual-file-system.js +29 -7
  104. package/dist/ai-service/app-interface/filesystem/virtual-file-system.js.map +1 -1
  105. package/dist/ai-service/app-interface/shell.d.ts +6 -0
  106. package/dist/ai-service/app-interface/shell.d.ts.map +1 -1
  107. package/dist/ai-service/app-interface/shell.js +8 -0
  108. package/dist/ai-service/app-interface/shell.js.map +1 -1
  109. package/dist/ai-service/app-skills/helpers.d.ts.map +1 -1
  110. package/dist/ai-service/app-skills/helpers.js +4 -2
  111. package/dist/ai-service/app-skills/helpers.js.map +1 -1
  112. package/dist/ai-service/attachments/store.d.ts +18 -2
  113. package/dist/ai-service/attachments/store.d.ts.map +1 -1
  114. package/dist/ai-service/attachments/store.js +102 -9
  115. package/dist/ai-service/attachments/store.js.map +1 -1
  116. package/dist/ai-service/attachments/uploaded-content-part.d.ts +5 -2
  117. package/dist/ai-service/attachments/uploaded-content-part.d.ts.map +1 -1
  118. package/dist/ai-service/attachments/uploaded-content-part.js +32 -0
  119. package/dist/ai-service/attachments/uploaded-content-part.js.map +1 -1
  120. package/dist/ai-service/chat/chat-session-store.d.ts +2 -2
  121. package/dist/ai-service/chat/chat-session-store.d.ts.map +1 -1
  122. package/dist/ai-service/chat/chat-session-store.js +45 -243
  123. package/dist/ai-service/chat/chat-session-store.js.map +1 -1
  124. package/dist/ai-service/chat/utils.d.ts +6 -0
  125. package/dist/ai-service/chat/utils.d.ts.map +1 -1
  126. package/dist/ai-service/chat/utils.js +47 -0
  127. package/dist/ai-service/chat/utils.js.map +1 -1
  128. package/dist/ai-service/features.d.ts +4 -0
  129. package/dist/ai-service/features.d.ts.map +1 -1
  130. package/dist/ai-service/features.js +4 -0
  131. package/dist/ai-service/features.js.map +1 -1
  132. package/dist/ai-service/index.d.ts +36 -11
  133. package/dist/ai-service/index.d.ts.map +1 -1
  134. package/dist/ai-service/index.js +228 -68
  135. package/dist/ai-service/index.js.map +1 -1
  136. package/dist/ai-service/judge/tools/playwright-action.d.ts +1 -1
  137. package/dist/ai-service/llm/client.d.ts.map +1 -1
  138. package/dist/ai-service/llm/client.js +4 -2
  139. package/dist/ai-service/llm/client.js.map +1 -1
  140. package/dist/ai-service/llm/stream/observers/retry-notification.d.ts.map +1 -1
  141. package/dist/ai-service/llm/stream/observers/retry-notification.js +4 -2
  142. package/dist/ai-service/llm/stream/observers/retry-notification.js.map +1 -1
  143. package/dist/ai-service/prompt-builder-service/classifiers/prompt-interpret-task.d.ts.map +1 -1
  144. package/dist/ai-service/prompt-builder-service/classifiers/prompt-interpret-task.js +1 -16
  145. package/dist/ai-service/prompt-builder-service/classifiers/prompt-interpret-task.js.map +1 -1
  146. package/dist/ai-service/prompt-builder-service/types.d.ts +2 -13
  147. package/dist/ai-service/prompt-builder-service/types.d.ts.map +1 -1
  148. package/dist/ai-service/prompt-builder-service/types.js.map +1 -1
  149. package/dist/ai-service/skills/system/_registry.generated.d.ts.map +1 -1
  150. package/dist/ai-service/skills/system/_registry.generated.js +6 -0
  151. package/dist/ai-service/skills/system/_registry.generated.js.map +1 -1
  152. package/dist/ai-service/skills/system/superblocks-migration/references/focused-debug.generated.d.ts +2 -0
  153. package/dist/ai-service/skills/system/superblocks-migration/references/focused-debug.generated.d.ts.map +1 -0
  154. package/dist/ai-service/skills/system/superblocks-migration/references/focused-debug.generated.js +58 -0
  155. package/dist/ai-service/skills/system/superblocks-migration/references/focused-debug.generated.js.map +1 -0
  156. package/dist/ai-service/skills/system/superblocks-migration/references/yaml-block-mapping.generated.d.ts +2 -0
  157. package/dist/ai-service/skills/system/superblocks-migration/references/yaml-block-mapping.generated.d.ts.map +1 -0
  158. package/dist/ai-service/skills/system/superblocks-migration/references/yaml-block-mapping.generated.js +107 -0
  159. package/dist/ai-service/skills/system/superblocks-migration/references/yaml-block-mapping.generated.js.map +1 -0
  160. package/dist/ai-service/skills/system/superblocks-migration/skill.generated.d.ts +2 -0
  161. package/dist/ai-service/skills/system/superblocks-migration/skill.generated.d.ts.map +1 -0
  162. package/dist/ai-service/skills/system/superblocks-migration/skill.generated.js +137 -0
  163. package/dist/ai-service/skills/system/superblocks-migration/skill.generated.js.map +1 -0
  164. package/dist/ai-service/state-machine/clark-fsm.d.ts +26 -13
  165. package/dist/ai-service/state-machine/clark-fsm.d.ts.map +1 -1
  166. package/dist/ai-service/state-machine/clark-fsm.js +12 -7
  167. package/dist/ai-service/state-machine/clark-fsm.js.map +1 -1
  168. package/dist/ai-service/state-machine/handlers/agent-planning.d.ts.map +1 -1
  169. package/dist/ai-service/state-machine/handlers/agent-planning.js +51 -27
  170. package/dist/ai-service/state-machine/handlers/agent-planning.js.map +1 -1
  171. package/dist/ai-service/state-machine/handlers/awaiting-user.d.ts.map +1 -1
  172. package/dist/ai-service/state-machine/handlers/awaiting-user.js +15 -6
  173. package/dist/ai-service/state-machine/handlers/awaiting-user.js.map +1 -1
  174. package/dist/ai-service/state-machine/handlers/idle.d.ts.map +1 -1
  175. package/dist/ai-service/state-machine/handlers/idle.js +4 -2
  176. package/dist/ai-service/state-machine/handlers/idle.js.map +1 -1
  177. package/dist/ai-service/state-machine/handlers/llm-generating.d.ts.map +1 -1
  178. package/dist/ai-service/state-machine/handlers/llm-generating.js +48 -15
  179. package/dist/ai-service/state-machine/handlers/llm-generating.js.map +1 -1
  180. package/dist/ai-service/state-machine/handlers/post-processing.d.ts +1 -1
  181. package/dist/ai-service/state-machine/handlers/post-processing.d.ts.map +1 -1
  182. package/dist/ai-service/state-machine/handlers/post-processing.js +23 -151
  183. package/dist/ai-service/state-machine/handlers/post-processing.js.map +1 -1
  184. package/dist/ai-service/state-machine/handlers/runtime-reviewing.d.ts.map +1 -1
  185. package/dist/ai-service/state-machine/handlers/runtime-reviewing.js +16 -8
  186. package/dist/ai-service/state-machine/handlers/runtime-reviewing.js.map +1 -1
  187. package/dist/ai-service/state-machine/helpers/change-info.d.ts.map +1 -1
  188. package/dist/ai-service/state-machine/helpers/change-info.js +2 -15
  189. package/dist/ai-service/state-machine/helpers/change-info.js.map +1 -1
  190. package/dist/ai-service/state-machine/helpers/peer.d.ts +3 -3
  191. package/dist/ai-service/state-machine/helpers/peer.d.ts.map +1 -1
  192. package/dist/ai-service/state-machine/helpers/peer.js +9 -23
  193. package/dist/ai-service/state-machine/helpers/peer.js.map +1 -1
  194. package/dist/ai-service/state-machine/helpers/stable-peer.d.ts +52 -0
  195. package/dist/ai-service/state-machine/helpers/stable-peer.d.ts.map +1 -0
  196. package/dist/ai-service/state-machine/helpers/stable-peer.js +141 -0
  197. package/dist/ai-service/state-machine/helpers/stable-peer.js.map +1 -0
  198. package/dist/ai-service/state-machine/mocks.d.ts.map +1 -1
  199. package/dist/ai-service/state-machine/mocks.js +0 -17
  200. package/dist/ai-service/state-machine/mocks.js.map +1 -1
  201. package/dist/ai-service/types.d.ts +2 -21
  202. package/dist/ai-service/types.d.ts.map +1 -1
  203. package/dist/ai-service/types.js.map +1 -1
  204. package/dist/ai-service/util/archive-extractors.d.ts +52 -0
  205. package/dist/ai-service/util/archive-extractors.d.ts.map +1 -0
  206. package/dist/ai-service/util/archive-extractors.js +278 -0
  207. package/dist/ai-service/util/archive-extractors.js.map +1 -0
  208. package/dist/codegen.d.ts +1 -22
  209. package/dist/codegen.d.ts.map +1 -1
  210. package/dist/codegen.js +1 -117
  211. package/dist/codegen.js.map +1 -1
  212. package/dist/components-manager.d.ts +0 -6
  213. package/dist/components-manager.d.ts.map +1 -1
  214. package/dist/components-manager.js +0 -27
  215. package/dist/components-manager.js.map +1 -1
  216. package/dist/file-sync-vite-plugin.d.ts.map +1 -1
  217. package/dist/file-sync-vite-plugin.js +47 -94
  218. package/dist/file-sync-vite-plugin.js.map +1 -1
  219. package/dist/file-system-manager.d.ts +2 -15
  220. package/dist/file-system-manager.d.ts.map +1 -1
  221. package/dist/file-system-manager.js +16 -128
  222. package/dist/file-system-manager.js.map +1 -1
  223. package/dist/git-service/live-branch.d.ts.map +1 -1
  224. package/dist/git-service/live-branch.js +15 -1
  225. package/dist/git-service/live-branch.js.map +1 -1
  226. package/dist/lock-service/index.d.ts.map +1 -1
  227. package/dist/lock-service/index.js +8 -5
  228. package/dist/lock-service/index.js.map +1 -1
  229. package/dist/migration/get-fullstack-template-dir.d.ts +37 -0
  230. package/dist/migration/get-fullstack-template-dir.d.ts.map +1 -0
  231. package/dist/migration/get-fullstack-template-dir.js +99 -0
  232. package/dist/migration/get-fullstack-template-dir.js.map +1 -0
  233. package/dist/migration/migration-checklist.d.ts +60 -0
  234. package/dist/migration/migration-checklist.d.ts.map +1 -0
  235. package/dist/migration/migration-checklist.js +230 -0
  236. package/dist/migration/migration-checklist.js.map +1 -0
  237. package/dist/migration/migration-routes.d.ts +23 -0
  238. package/dist/migration/migration-routes.d.ts.map +1 -0
  239. package/dist/migration/migration-routes.js +533 -0
  240. package/dist/migration/migration-routes.js.map +1 -0
  241. package/dist/migration/restructure.d.ts +76 -0
  242. package/dist/migration/restructure.d.ts.map +1 -0
  243. package/dist/migration/restructure.js +446 -0
  244. package/dist/migration/restructure.js.map +1 -0
  245. package/dist/migration/translation-prompt.d.ts +22 -0
  246. package/dist/migration/translation-prompt.d.ts.map +1 -0
  247. package/dist/migration/translation-prompt.js +27 -0
  248. package/dist/migration/translation-prompt.js.map +1 -0
  249. package/dist/migration-templates/app-fullstack/client/App.tsx +17 -0
  250. package/dist/migration-templates/app-fullstack/client/components/common/sonner.tsx +20 -0
  251. package/dist/migration-templates/app-fullstack/client/components/hooks/use-active-page.ts +73 -0
  252. package/dist/migration-templates/app-fullstack/client/components/hooks/use-mobile.ts +21 -0
  253. package/dist/migration-templates/app-fullstack/client/components/ui/accordion.tsx +197 -0
  254. package/dist/migration-templates/app-fullstack/client/components/ui/area-chart.tsx +432 -0
  255. package/dist/migration-templates/app-fullstack/client/components/ui/aspect-ratio.tsx +45 -0
  256. package/dist/migration-templates/app-fullstack/client/components/ui/avatar.tsx +117 -0
  257. package/dist/migration-templates/app-fullstack/client/components/ui/badge.tsx +143 -0
  258. package/dist/migration-templates/app-fullstack/client/components/ui/bar-chart.tsx +390 -0
  259. package/dist/migration-templates/app-fullstack/client/components/ui/breadcrumb.tsx +259 -0
  260. package/dist/migration-templates/app-fullstack/client/components/ui/button.tsx +182 -0
  261. package/dist/migration-templates/app-fullstack/client/components/ui/calendar.tsx +300 -0
  262. package/dist/migration-templates/app-fullstack/client/components/ui/card.tsx +129 -0
  263. package/dist/migration-templates/app-fullstack/client/components/ui/chart.tsx +403 -0
  264. package/dist/migration-templates/app-fullstack/client/components/ui/chat.tsx +2303 -0
  265. package/dist/migration-templates/app-fullstack/client/components/ui/checkbox.tsx +97 -0
  266. package/dist/migration-templates/app-fullstack/client/components/ui/code-block-content.tsx +66 -0
  267. package/dist/migration-templates/app-fullstack/client/components/ui/date-range-picker.tsx +396 -0
  268. package/dist/migration-templates/app-fullstack/client/components/ui/dialog.tsx +223 -0
  269. package/dist/migration-templates/app-fullstack/client/components/ui/dropdown-menu.tsx +284 -0
  270. package/dist/migration-templates/app-fullstack/client/components/ui/file-dropzone.tsx +395 -0
  271. package/dist/migration-templates/app-fullstack/client/components/ui/file-input.tsx +166 -0
  272. package/dist/migration-templates/app-fullstack/client/components/ui/hover-card.tsx +162 -0
  273. package/dist/migration-templates/app-fullstack/client/components/ui/icon.tsx +133 -0
  274. package/dist/migration-templates/app-fullstack/client/components/ui/image.tsx +68 -0
  275. package/dist/migration-templates/app-fullstack/client/components/ui/input.tsx +219 -0
  276. package/dist/migration-templates/app-fullstack/client/components/ui/label.tsx +55 -0
  277. package/dist/migration-templates/app-fullstack/client/components/ui/line-chart.tsx +380 -0
  278. package/dist/migration-templates/app-fullstack/client/components/ui/link.tsx +139 -0
  279. package/dist/migration-templates/app-fullstack/client/components/ui/navigation-menu.tsx +345 -0
  280. package/dist/migration-templates/app-fullstack/client/components/ui/pagination.tsx +192 -0
  281. package/dist/migration-templates/app-fullstack/client/components/ui/pie-chart.tsx +295 -0
  282. package/dist/migration-templates/app-fullstack/client/components/ui/popover.tsx +162 -0
  283. package/dist/migration-templates/app-fullstack/client/components/ui/progress.tsx +69 -0
  284. package/dist/migration-templates/app-fullstack/client/components/ui/radar-chart.tsx +386 -0
  285. package/dist/migration-templates/app-fullstack/client/components/ui/radial-chart.tsx +402 -0
  286. package/dist/migration-templates/app-fullstack/client/components/ui/scroll-area.tsx +86 -0
  287. package/dist/migration-templates/app-fullstack/client/components/ui/select.tsx +229 -0
  288. package/dist/migration-templates/app-fullstack/client/components/ui/separator.tsx +62 -0
  289. package/dist/migration-templates/app-fullstack/client/components/ui/sheet.tsx +234 -0
  290. package/dist/migration-templates/app-fullstack/client/components/ui/sidebar.tsx +974 -0
  291. package/dist/migration-templates/app-fullstack/client/components/ui/skeleton.tsx +13 -0
  292. package/dist/migration-templates/app-fullstack/client/components/ui/slider.tsx +198 -0
  293. package/dist/migration-templates/app-fullstack/client/components/ui/switch.tsx +95 -0
  294. package/dist/migration-templates/app-fullstack/client/components/ui/table.tsx +145 -0
  295. package/dist/migration-templates/app-fullstack/client/components/ui/tabs.tsx +87 -0
  296. package/dist/migration-templates/app-fullstack/client/components/ui/textarea.tsx +148 -0
  297. package/dist/migration-templates/app-fullstack/client/components/ui/toggle-group.tsx +225 -0
  298. package/dist/migration-templates/app-fullstack/client/components/ui/toggle.tsx +150 -0
  299. package/dist/migration-templates/app-fullstack/client/components/ui/tooltip.tsx +175 -0
  300. package/dist/migration-templates/app-fullstack/client/hooks/useApi.ts +25 -0
  301. package/dist/migration-templates/app-fullstack/client/hooks/useApiData.ts +10 -0
  302. package/dist/migration-templates/app-fullstack/client/index.css +131 -0
  303. package/dist/migration-templates/app-fullstack/client/lib/executeApi.ts +9 -0
  304. package/dist/migration-templates/app-fullstack/client/lib/utils.ts +6 -0
  305. package/dist/migration-templates/app-fullstack/client/pages/Page1/index.tsx +3 -0
  306. package/dist/migration-templates/app-fullstack/client/root.tsx +17 -0
  307. package/dist/migration-templates/app-fullstack/client/router.tsx +48 -0
  308. package/dist/migration-templates/app-fullstack/client/types/node.d.ts +9 -0
  309. package/dist/migration-templates/app-fullstack/components.json +21 -0
  310. package/dist/migration-templates/app-fullstack/eslint.config.js +108 -0
  311. package/dist/migration-templates/app-fullstack/package.json +89 -0
  312. package/dist/migration-templates/app-fullstack/server/.gitkeep +0 -0
  313. package/dist/migration-templates/app-fullstack/server/apis/index.ts +22 -0
  314. package/dist/migration-templates/app-fullstack/server/index.ts +2 -0
  315. package/dist/migration-templates/app-fullstack/tsconfig.client.json +27 -0
  316. package/dist/migration-templates/app-fullstack/tsconfig.eslint.json +8 -0
  317. package/dist/migration-templates/app-fullstack/tsconfig.json +25 -0
  318. package/dist/migration-templates/app-fullstack/tsconfig.server.json +13 -0
  319. package/dist/migration-templates/app-fullstack/vite.config.ts +17 -0
  320. package/dist/parsing/imports.d.ts +0 -16
  321. package/dist/parsing/imports.d.ts.map +1 -1
  322. package/dist/parsing/imports.js +0 -68
  323. package/dist/parsing/imports.js.map +1 -1
  324. package/dist/parsing/jsx.d.ts +0 -2
  325. package/dist/parsing/jsx.d.ts.map +1 -1
  326. package/dist/parsing/jsx.js +0 -62
  327. package/dist/parsing/jsx.js.map +1 -1
  328. package/dist/socket-manager.d.ts.map +1 -1
  329. package/dist/socket-manager.js +109 -32
  330. package/dist/socket-manager.js.map +1 -1
  331. package/dist/source-tracker.d.ts +7 -85
  332. package/dist/source-tracker.d.ts.map +1 -1
  333. package/dist/source-tracker.js +19 -695
  334. package/dist/source-tracker.js.map +1 -1
  335. package/dist/sync-service/index.d.ts +79 -2
  336. package/dist/sync-service/index.d.ts.map +1 -1
  337. package/dist/sync-service/index.js +139 -10
  338. package/dist/sync-service/index.js.map +1 -1
  339. package/package.json +11 -9
  340. package/dist/ai-service/artifacts/bolt.d.ts +0 -8
  341. package/dist/ai-service/artifacts/bolt.d.ts.map +0 -1
  342. package/dist/ai-service/artifacts/bolt.js +0 -92
  343. package/dist/ai-service/artifacts/bolt.js.map +0 -1
  344. package/dist/ai-service/result-buffer/bolt.d.ts +0 -18
  345. package/dist/ai-service/result-buffer/bolt.d.ts.map +0 -1
  346. package/dist/ai-service/result-buffer/bolt.js +0 -100
  347. package/dist/ai-service/result-buffer/bolt.js.map +0 -1
  348. package/dist/ai-service/result-buffer/shared.d.ts +0 -17
  349. package/dist/ai-service/result-buffer/shared.d.ts.map +0 -1
  350. package/dist/ai-service/result-buffer/shared.js +0 -7
  351. package/dist/ai-service/result-buffer/shared.js.map +0 -1
  352. package/dist/inject-no-select.d.ts +0 -15
  353. package/dist/inject-no-select.d.ts.map +0 -1
  354. package/dist/inject-no-select.js +0 -175
  355. package/dist/inject-no-select.js.map +0 -1
@@ -0,0 +1,2303 @@
1
+ "use client";
2
+
3
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
4
+ import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
5
+ import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
6
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
7
+ import type { UIMessage } from "ai";
8
+ import type { ChatStatus } from "ai";
9
+ import type { ToolUIPart } from "ai";
10
+ import useEmblaCarousel, {
11
+ type UseEmblaCarouselType,
12
+ } from "embla-carousel-react";
13
+ import {
14
+ ArrowDownIcon,
15
+ CheckIcon,
16
+ CopyIcon,
17
+ SendIcon,
18
+ Loader2Icon,
19
+ SquareIcon,
20
+ XIcon,
21
+ } from "lucide-react";
22
+ import {
23
+ ChevronRightIcon,
24
+ ChevronLeftIcon,
25
+ ArrowLeft,
26
+ ArrowRight,
27
+ BrainIcon,
28
+ ChevronDownIcon,
29
+ BookIcon,
30
+ SearchIcon,
31
+ WrenchIcon,
32
+ CheckCircleIcon,
33
+ CircleIcon,
34
+ ClockIcon,
35
+ XCircleIcon,
36
+ ArrowLeftIcon,
37
+ ArrowRightIcon,
38
+ } from "lucide-react";
39
+ import type React from "react";
40
+ import type {
41
+ ComponentProps,
42
+ HTMLAttributes,
43
+ KeyboardEventHandler,
44
+ ComponentPropsWithRef,
45
+ ReactNode,
46
+ } from "react";
47
+ import {
48
+ useCallback,
49
+ Children,
50
+ useEffect,
51
+ useState,
52
+ useRef,
53
+ createContext,
54
+ useContext,
55
+ useMemo,
56
+ memo,
57
+ lazy,
58
+ Suspense,
59
+ } from "react";
60
+ import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
61
+
62
+ import { registerComponent } from "@superblocksteam/library";
63
+ import {
64
+ Prop,
65
+ Section,
66
+ PropsCategory,
67
+ type PropertiesPanelDefinition,
68
+ type EditorConfig,
69
+ } from "@superblocksteam/library";
70
+
71
+ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
72
+ import { Badge } from "@/components/ui/badge";
73
+ import { Button } from "@/components/ui/button";
74
+ import {
75
+ Select,
76
+ SelectContent,
77
+ SelectItem,
78
+ SelectTrigger,
79
+ SelectValue,
80
+ } from "@/components/ui/select";
81
+ import { Textarea } from "@/components/ui/textarea";
82
+ import { cn } from "@/lib/utils";
83
+ // Lazy load syntax highlighter to avoid loading large bundle when Chat is imported but not rendered
84
+ // We intentionally diverge from shadcn here so we can increase loading performance in edit mode
85
+ const LazyCodeBlockContent = lazy(() => import("./code-block-content"));
86
+
87
+ import { useControllableState } from "@radix-ui/react-use-controllable-state";
88
+ import { Streamdown } from "streamdown";
89
+
90
+ // ===================================
91
+ // COLLAPSIBLE COMPONENTS
92
+ // ===================================
93
+
94
+ function Collapsible({
95
+ ...props
96
+ }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
97
+ return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
98
+ }
99
+
100
+ function CollapsibleTrigger({
101
+ ...props
102
+ }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
103
+ return (
104
+ <CollapsiblePrimitive.CollapsibleTrigger
105
+ data-slot="collapsible-trigger"
106
+ {...props}
107
+ />
108
+ );
109
+ }
110
+
111
+ function CollapsibleContent({
112
+ ...props
113
+ }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
114
+ return (
115
+ <CollapsiblePrimitive.CollapsibleContent
116
+ data-slot="collapsible-content"
117
+ {...props}
118
+ />
119
+ );
120
+ }
121
+
122
+ // ===================================
123
+ // TOOLTIP COMPONENTS
124
+ // ===================================
125
+
126
+ function TooltipProvider({
127
+ delayDuration = 0,
128
+ ...props
129
+ }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
130
+ return (
131
+ <TooltipPrimitive.Provider
132
+ data-slot="tooltip-provider"
133
+ delayDuration={delayDuration}
134
+ {...props}
135
+ />
136
+ );
137
+ }
138
+
139
+ function Tooltip({
140
+ ...props
141
+ }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
142
+ return (
143
+ <TooltipProvider>
144
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
145
+ </TooltipProvider>
146
+ );
147
+ }
148
+
149
+ function TooltipTrigger({
150
+ ...props
151
+ }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
152
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
153
+ }
154
+
155
+ function TooltipContent({
156
+ className,
157
+ sideOffset = 0,
158
+ children,
159
+ ...props
160
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
161
+ return (
162
+ <TooltipPrimitive.Portal>
163
+ <TooltipPrimitive.Content
164
+ data-slot="tooltip-content"
165
+ sideOffset={sideOffset}
166
+ className={cn(
167
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
168
+ className,
169
+ )}
170
+ {...props}
171
+ >
172
+ {children}
173
+ <TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
174
+ </TooltipPrimitive.Content>
175
+ </TooltipPrimitive.Portal>
176
+ );
177
+ }
178
+
179
+ // ===================================
180
+ // HOVER CARD COMPONENTS
181
+ // ===================================
182
+
183
+ function HoverCard({
184
+ ...props
185
+ }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
186
+ return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;
187
+ }
188
+
189
+ function HoverCardTrigger({
190
+ ...props
191
+ }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
192
+ return (
193
+ <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
194
+ );
195
+ }
196
+
197
+ function HoverCardContent({
198
+ className,
199
+ align = "center",
200
+ sideOffset = 4,
201
+ ...props
202
+ }: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
203
+ return (
204
+ <HoverCardPrimitive.Portal data-slot="hover-card-portal">
205
+ <HoverCardPrimitive.Content
206
+ data-slot="hover-card-content"
207
+ align={align}
208
+ sideOffset={sideOffset}
209
+ className={cn(
210
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out 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 z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
211
+ className,
212
+ )}
213
+ {...props}
214
+ />
215
+ </HoverCardPrimitive.Portal>
216
+ );
217
+ }
218
+
219
+ // ===================================
220
+ // SCROLL AREA COMPONENTS
221
+ // ===================================
222
+
223
+ function ScrollArea({
224
+ className,
225
+ children,
226
+ ...props
227
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
228
+ return (
229
+ <ScrollAreaPrimitive.Root
230
+ data-slot="scroll-area"
231
+ className={cn("relative", className)}
232
+ {...props}
233
+ >
234
+ <ScrollAreaPrimitive.Viewport
235
+ data-slot="scroll-area-viewport"
236
+ className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
237
+ >
238
+ {children}
239
+ </ScrollAreaPrimitive.Viewport>
240
+ <ScrollBar />
241
+ <ScrollAreaPrimitive.Corner />
242
+ </ScrollAreaPrimitive.Root>
243
+ );
244
+ }
245
+
246
+ function ScrollBar({
247
+ className,
248
+ orientation = "vertical",
249
+ ...props
250
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
251
+ return (
252
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
253
+ data-slot="scroll-area-scrollbar"
254
+ orientation={orientation}
255
+ className={cn(
256
+ "flex touch-none p-px transition-colors select-none",
257
+ orientation === "vertical" &&
258
+ "h-full w-2.5 border-l border-l-transparent",
259
+ orientation === "horizontal" &&
260
+ "h-2.5 flex-col border-t border-t-transparent",
261
+ className,
262
+ )}
263
+ {...props}
264
+ >
265
+ <ScrollAreaPrimitive.ScrollAreaThumb
266
+ data-slot="scroll-area-thumb"
267
+ className="bg-border relative flex-1 rounded-full"
268
+ />
269
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
270
+ );
271
+ }
272
+
273
+ // ===================================
274
+ // CAROUSEL COMPONENTS
275
+ // ===================================
276
+
277
+ type CarouselApi = UseEmblaCarouselType[1];
278
+ type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
279
+ type CarouselOptions = UseCarouselParameters[0];
280
+ type CarouselPlugin = UseCarouselParameters[1];
281
+
282
+ interface CarouselProps {
283
+ opts?: CarouselOptions;
284
+ plugins?: CarouselPlugin;
285
+ orientation?: "horizontal" | "vertical";
286
+ setApi?: (api: CarouselApi) => void;
287
+ }
288
+
289
+ type CarouselContextProps = {
290
+ carouselRef: ReturnType<typeof useEmblaCarousel>[0];
291
+ api: ReturnType<typeof useEmblaCarousel>[1];
292
+ scrollPrev: () => void;
293
+ scrollNext: () => void;
294
+ canScrollPrev: boolean;
295
+ canScrollNext: boolean;
296
+ } & CarouselProps;
297
+
298
+ const CarouselContext = createContext<CarouselContextProps | null>(null);
299
+
300
+ function useCarousel() {
301
+ const context = useContext(CarouselContext);
302
+
303
+ if (!context) {
304
+ throw new Error("useCarousel must be used within a <Carousel />");
305
+ }
306
+
307
+ return context;
308
+ }
309
+
310
+ function Carousel({
311
+ orientation = "horizontal",
312
+ opts,
313
+ setApi,
314
+ plugins,
315
+ className,
316
+ children,
317
+ ...props
318
+ }: React.ComponentProps<"div"> & CarouselProps) {
319
+ const [carouselRef, api] = useEmblaCarousel(
320
+ {
321
+ ...opts,
322
+ axis: orientation === "horizontal" ? "x" : "y",
323
+ },
324
+ plugins,
325
+ );
326
+ const [canScrollPrev, setCanScrollPrev] = useState(false);
327
+ const [canScrollNext, setCanScrollNext] = useState(false);
328
+ const isInitializedRef = useRef(false);
329
+
330
+ const scrollPrev = useCallback(() => {
331
+ api?.scrollPrev();
332
+ }, [api]);
333
+
334
+ const scrollNext = useCallback(() => {
335
+ api?.scrollNext();
336
+ }, [api]);
337
+
338
+ const handleKeyDown = useCallback(
339
+ (event: React.KeyboardEvent<HTMLDivElement>) => {
340
+ if (event.key === "ArrowLeft") {
341
+ event.preventDefault();
342
+ scrollPrev();
343
+ } else if (event.key === "ArrowRight") {
344
+ event.preventDefault();
345
+ scrollNext();
346
+ }
347
+ },
348
+ [scrollPrev, scrollNext],
349
+ );
350
+
351
+ useEffect(() => {
352
+ if (!api || !setApi) return;
353
+ setApi(api);
354
+ }, [api, setApi]);
355
+
356
+ useEffect(() => {
357
+ if (!api) return;
358
+
359
+ const handleSelect = () => {
360
+ setCanScrollPrev(api.canScrollPrev());
361
+ setCanScrollNext(api.canScrollNext());
362
+ };
363
+
364
+ // Initialize state when API first becomes available
365
+ if (!isInitializedRef.current) {
366
+ handleSelect();
367
+ isInitializedRef.current = true;
368
+ }
369
+
370
+ api.on("reInit", handleSelect);
371
+ api.on("select", handleSelect);
372
+
373
+ return () => {
374
+ api.off("reInit", handleSelect);
375
+ api.off("select", handleSelect);
376
+ };
377
+ }, [api]);
378
+
379
+ return (
380
+ <CarouselContext.Provider
381
+ value={{
382
+ carouselRef,
383
+ api: api,
384
+ opts,
385
+ orientation:
386
+ orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
387
+ scrollPrev,
388
+ scrollNext,
389
+ canScrollPrev,
390
+ canScrollNext,
391
+ }}
392
+ >
393
+ <div
394
+ onKeyDownCapture={handleKeyDown}
395
+ className={cn("relative", className)}
396
+ role="region"
397
+ aria-roledescription="carousel"
398
+ data-slot="carousel"
399
+ {...props}
400
+ >
401
+ {children}
402
+ </div>
403
+ </CarouselContext.Provider>
404
+ );
405
+ }
406
+
407
+ function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
408
+ const { carouselRef, orientation } = useCarousel();
409
+
410
+ return (
411
+ <div
412
+ ref={carouselRef}
413
+ className="overflow-hidden"
414
+ data-slot="carousel-content"
415
+ >
416
+ <div
417
+ className={cn(
418
+ "flex",
419
+ orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
420
+ className,
421
+ )}
422
+ {...props}
423
+ />
424
+ </div>
425
+ );
426
+ }
427
+
428
+ function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
429
+ const { orientation } = useCarousel();
430
+
431
+ return (
432
+ <div
433
+ role="group"
434
+ aria-roledescription="slide"
435
+ data-slot="carousel-item"
436
+ className={cn(
437
+ "min-w-0 shrink-0 grow-0 basis-full",
438
+ orientation === "horizontal" ? "pl-4" : "pt-4",
439
+ className,
440
+ )}
441
+ {...props}
442
+ />
443
+ );
444
+ }
445
+
446
+ function CarouselPrevious({
447
+ className,
448
+ variant = "outline",
449
+ size = "icon",
450
+ ...props
451
+ }: React.ComponentProps<typeof Button>) {
452
+ const { orientation, scrollPrev, canScrollPrev } = useCarousel();
453
+
454
+ return (
455
+ <Button
456
+ data-slot="carousel-previous"
457
+ variant={variant}
458
+ size={size}
459
+ className={cn(
460
+ "absolute size-8 rounded-full",
461
+ orientation === "horizontal"
462
+ ? "top-1/2 -left-12 -translate-y-1/2"
463
+ : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
464
+ className,
465
+ )}
466
+ disabled={!canScrollPrev}
467
+ onClick={scrollPrev}
468
+ {...props}
469
+ >
470
+ <ArrowLeft />
471
+ <span className="sr-only">Previous slide</span>
472
+ </Button>
473
+ );
474
+ }
475
+
476
+ function CarouselNext({
477
+ className,
478
+ variant = "outline",
479
+ size = "icon",
480
+ ...props
481
+ }: React.ComponentProps<typeof Button>) {
482
+ const { orientation, scrollNext, canScrollNext } = useCarousel();
483
+
484
+ return (
485
+ <Button
486
+ data-slot="carousel-next"
487
+ variant={variant}
488
+ size={size}
489
+ className={cn(
490
+ "absolute size-8 rounded-full",
491
+ orientation === "horizontal"
492
+ ? "top-1/2 -right-12 -translate-y-1/2"
493
+ : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
494
+ className,
495
+ )}
496
+ disabled={!canScrollNext}
497
+ onClick={scrollNext}
498
+ {...props}
499
+ >
500
+ <ArrowRight />
501
+ <span className="sr-only">Next slide</span>
502
+ </Button>
503
+ );
504
+ }
505
+
506
+ // ===================================
507
+ // CONVERSATION COMPONENTS
508
+ // ===================================
509
+
510
+ type ConversationProps = ComponentProps<typeof StickToBottom>;
511
+
512
+ const Conversation = ({ className, ...props }: ConversationProps) => (
513
+ <StickToBottom
514
+ className={cn("relative flex-1 overflow-y-auto", className)}
515
+ initial="smooth"
516
+ resize="smooth"
517
+ role="log"
518
+ {...props}
519
+ />
520
+ );
521
+
522
+ type ConversationContentProps = ComponentProps<typeof StickToBottom.Content>;
523
+
524
+ const ConversationContent = ({
525
+ className,
526
+ ...props
527
+ }: ConversationContentProps) => (
528
+ <StickToBottom.Content className={cn("p-4", className)} {...props} />
529
+ );
530
+
531
+ type ConversationScrollButtonProps = ComponentProps<typeof Button>;
532
+
533
+ const ConversationScrollButton = ({
534
+ className,
535
+ ...props
536
+ }: ConversationScrollButtonProps) => {
537
+ const { isAtBottom, scrollToBottom } = useStickToBottomContext();
538
+
539
+ const handleScrollToBottom = useCallback(() => {
540
+ void scrollToBottom();
541
+ }, [scrollToBottom]);
542
+
543
+ return (
544
+ !isAtBottom && (
545
+ <Button
546
+ className={cn(
547
+ "absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full",
548
+ className,
549
+ )}
550
+ onClick={handleScrollToBottom}
551
+ size="icon"
552
+ type="button"
553
+ variant="outline"
554
+ {...props}
555
+ >
556
+ <ArrowDownIcon className="size-4" />
557
+ </Button>
558
+ )
559
+ );
560
+ };
561
+
562
+ // ===================================
563
+ // MESSAGE COMPONENTS
564
+ // ===================================
565
+
566
+ type MessageProps = HTMLAttributes<HTMLDivElement> & {
567
+ from: UIMessage["role"];
568
+ };
569
+
570
+ const Message = ({ className, from, ...props }: MessageProps) => (
571
+ <div
572
+ className={cn(
573
+ "group flex w-full items-end justify-end gap-2 py-4",
574
+ from === "user" ? "is-user" : "is-assistant flex-row-reverse justify-end",
575
+ "[&>div]:max-w-[80%]",
576
+ className,
577
+ )}
578
+ {...props}
579
+ />
580
+ );
581
+
582
+ type MessageContentProps = HTMLAttributes<HTMLDivElement>;
583
+
584
+ const MessageContent = ({
585
+ children,
586
+ className,
587
+ ...props
588
+ }: MessageContentProps) => (
589
+ <div
590
+ className={cn(
591
+ "flex flex-col gap-2 overflow-hidden rounded-lg px-4 py-3 text-foreground text-sm",
592
+ "group-[.is-user]:bg-primary group-[.is-user]:text-primary-foreground",
593
+ "group-[.is-assistant]:bg-secondary group-[.is-assistant]:text-foreground",
594
+ "is-user:dark",
595
+ className,
596
+ )}
597
+ {...props}
598
+ >
599
+ {children}
600
+ </div>
601
+ );
602
+
603
+ type MessageAvatarProps = ComponentProps<typeof Avatar> & {
604
+ src: string;
605
+ name?: string;
606
+ };
607
+
608
+ const MessageAvatar = ({
609
+ src,
610
+ name,
611
+ className,
612
+ ...props
613
+ }: MessageAvatarProps) => (
614
+ <Avatar className={cn("size-8 ring-1 ring-border", className)} {...props}>
615
+ <AvatarImage alt="" className="mt-0 mb-0" src={src} />
616
+ <AvatarFallback>{name?.slice(0, 2) || "ME"}</AvatarFallback>
617
+ </Avatar>
618
+ );
619
+
620
+ // ===================================
621
+ // PROMPT INPUT COMPONENTS
622
+ // ===================================
623
+
624
+ type PromptInputProps = HTMLAttributes<HTMLFormElement>;
625
+
626
+ const PromptInput = ({ className, ...props }: PromptInputProps) => (
627
+ <form
628
+ className={cn(
629
+ "w-full divide-y overflow-hidden rounded-xl border bg-background shadow-sm",
630
+ className,
631
+ )}
632
+ {...props}
633
+ />
634
+ );
635
+
636
+ type PromptInputTextareaProps = ComponentProps<typeof Textarea> & {
637
+ minHeight?: number;
638
+ maxHeight?: number;
639
+ };
640
+
641
+ const PromptInputTextarea = ({
642
+ onChange,
643
+ className,
644
+ placeholder = "What would you like to know?",
645
+ ...props
646
+ }: PromptInputTextareaProps) => {
647
+ const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = (e) => {
648
+ if (e.key === "Enter") {
649
+ // Don't submit if IME composition is in progress
650
+ if (e.nativeEvent.isComposing) {
651
+ return;
652
+ }
653
+
654
+ if (e.shiftKey) {
655
+ // Allow newline
656
+ return;
657
+ }
658
+
659
+ // Submit on Enter (without Shift)
660
+ e.preventDefault();
661
+ const form = e.currentTarget.form;
662
+ if (form) {
663
+ form.requestSubmit();
664
+ }
665
+ }
666
+ };
667
+
668
+ return (
669
+ <Textarea
670
+ className={cn(
671
+ "w-full resize-none rounded-none border-none p-3 shadow-none outline-none ring-0",
672
+ "field-sizing-content max-h-[6lh] bg-transparent dark:bg-transparent",
673
+ "focus-visible:ring-0",
674
+ className,
675
+ )}
676
+ name="message"
677
+ onChange={(e) => {
678
+ onChange?.(e);
679
+ }}
680
+ onKeyDown={handleKeyDown}
681
+ placeholder={placeholder}
682
+ {...props}
683
+ />
684
+ );
685
+ };
686
+
687
+ type PromptInputToolbarProps = HTMLAttributes<HTMLDivElement>;
688
+
689
+ const PromptInputToolbar = ({
690
+ className,
691
+ ...props
692
+ }: PromptInputToolbarProps) => (
693
+ <div
694
+ className={cn("flex items-center justify-between p-1", className)}
695
+ {...props}
696
+ />
697
+ );
698
+
699
+ type PromptInputToolsProps = HTMLAttributes<HTMLDivElement>;
700
+
701
+ const PromptInputTools = ({ className, ...props }: PromptInputToolsProps) => (
702
+ <div
703
+ className={cn(
704
+ "flex items-center gap-1",
705
+ "[&_button:first-child]:rounded-bl-xl",
706
+ className,
707
+ )}
708
+ {...props}
709
+ />
710
+ );
711
+
712
+ type PromptInputButtonProps = ComponentProps<typeof Button>;
713
+
714
+ const PromptInputButton = ({
715
+ variant = "ghost",
716
+ className,
717
+ size,
718
+ ...props
719
+ }: PromptInputButtonProps) => {
720
+ const newSize =
721
+ (size ?? Children.count(props.children) > 1) ? "default" : "icon";
722
+
723
+ return (
724
+ <Button
725
+ className={cn(
726
+ "shrink-0 gap-1.5 rounded-lg",
727
+ variant === "ghost" && "text-muted-foreground",
728
+ newSize === "default" && "px-3",
729
+ className,
730
+ )}
731
+ size={newSize}
732
+ type="button"
733
+ variant={variant}
734
+ {...props}
735
+ />
736
+ );
737
+ };
738
+
739
+ type PromptInputSubmitProps = ComponentProps<typeof Button> & {
740
+ status?: ChatStatus;
741
+ };
742
+
743
+ const PromptInputSubmit = ({
744
+ className,
745
+ variant = "default",
746
+ size = "icon",
747
+ status,
748
+ children,
749
+ ...props
750
+ }: PromptInputSubmitProps) => {
751
+ let Icon = <SendIcon className="size-4" />;
752
+
753
+ if (status === "submitted") {
754
+ Icon = <Loader2Icon className="size-4 animate-spin" />;
755
+ } else if (status === "streaming") {
756
+ Icon = <SquareIcon className="size-4" />;
757
+ } else if (status === "error") {
758
+ Icon = <XIcon className="size-4" />;
759
+ }
760
+
761
+ return (
762
+ <Button
763
+ className={cn("gap-1.5 rounded-lg", className)}
764
+ size={size}
765
+ type="submit"
766
+ variant={variant}
767
+ {...props}
768
+ >
769
+ {children ?? Icon}
770
+ </Button>
771
+ );
772
+ };
773
+
774
+ type PromptInputModelSelectProps = ComponentProps<typeof Select>;
775
+
776
+ const PromptInputModelSelect = (props: PromptInputModelSelectProps) => (
777
+ <Select {...props} />
778
+ );
779
+
780
+ type PromptInputModelSelectTriggerProps = ComponentProps<typeof SelectTrigger>;
781
+
782
+ const PromptInputModelSelectTrigger = ({
783
+ className,
784
+ ...props
785
+ }: PromptInputModelSelectTriggerProps) => (
786
+ <SelectTrigger
787
+ className={cn(
788
+ "border-none bg-transparent font-medium text-muted-foreground shadow-none transition-colors",
789
+ 'hover:bg-accent hover:text-foreground [&[aria-expanded="true"]]:bg-accent [&[aria-expanded="true"]]:text-foreground',
790
+ className,
791
+ )}
792
+ {...props}
793
+ />
794
+ );
795
+
796
+ type PromptInputModelSelectContentProps = ComponentProps<typeof SelectContent>;
797
+
798
+ const PromptInputModelSelectContent = ({
799
+ className,
800
+ ...props
801
+ }: PromptInputModelSelectContentProps) => (
802
+ <SelectContent className={cn(className)} {...props} />
803
+ );
804
+
805
+ type PromptInputModelSelectItemProps = ComponentProps<typeof SelectItem>;
806
+
807
+ const PromptInputModelSelectItem = ({
808
+ className,
809
+ ...props
810
+ }: PromptInputModelSelectItemProps) => (
811
+ <SelectItem className={cn(className)} {...props} />
812
+ );
813
+
814
+ type PromptInputModelSelectValueProps = ComponentProps<typeof SelectValue>;
815
+
816
+ const PromptInputModelSelectValue = ({
817
+ className,
818
+ ...props
819
+ }: PromptInputModelSelectValueProps) => (
820
+ <SelectValue className={cn(className)} {...props} />
821
+ );
822
+
823
+ // ===================================
824
+ // SUGGESTION COMPONENTS
825
+ // ===================================
826
+
827
+ type SuggestionsProps = ComponentProps<typeof ScrollArea>;
828
+
829
+ const Suggestions = ({ className, children, ...props }: SuggestionsProps) => (
830
+ <ScrollArea className="w-full overflow-x-auto whitespace-nowrap" {...props}>
831
+ <div className={cn("flex w-max flex-nowrap items-center gap-2", className)}>
832
+ {children}
833
+ </div>
834
+ <ScrollBar className="hidden" orientation="horizontal" />
835
+ </ScrollArea>
836
+ );
837
+
838
+ type SuggestionProps = Omit<ComponentProps<typeof Button>, "onClick"> & {
839
+ suggestion: string;
840
+ onClick?: (suggestion: string) => void;
841
+ };
842
+
843
+ const Suggestion = ({
844
+ suggestion,
845
+ onClick,
846
+ className,
847
+ variant = "outline",
848
+ size = "sm",
849
+ children,
850
+ ...props
851
+ }: SuggestionProps) => {
852
+ const handleClick = () => {
853
+ onClick?.(suggestion);
854
+ };
855
+
856
+ return (
857
+ <Button
858
+ className={cn("cursor-pointer rounded-full px-4", className)}
859
+ onClick={handleClick}
860
+ size={size}
861
+ type="button"
862
+ variant={variant}
863
+ {...props}
864
+ >
865
+ {children || suggestion}
866
+ </Button>
867
+ );
868
+ };
869
+
870
+ // ===================================
871
+ // ACTIONS COMPONENTS
872
+ // ===================================
873
+
874
+ type ActionsProps = ComponentProps<"div">;
875
+
876
+ const Actions = ({ className, children, ...props }: ActionsProps) => (
877
+ <div className={cn("flex items-center gap-1", className)} {...props}>
878
+ {children}
879
+ </div>
880
+ );
881
+
882
+ type ActionProps = ComponentProps<typeof Button> & {
883
+ tooltip?: string;
884
+ label?: string;
885
+ };
886
+
887
+ const Action = ({
888
+ tooltip,
889
+ children,
890
+ label,
891
+ className,
892
+ variant = "ghost",
893
+ size = "sm",
894
+ ...props
895
+ }: ActionProps) => {
896
+ const button = (
897
+ <Button
898
+ className={cn(
899
+ "size-9 p-1.5 text-muted-foreground hover:text-foreground relative",
900
+ className,
901
+ )}
902
+ size={size}
903
+ type="button"
904
+ variant={variant}
905
+ {...props}
906
+ >
907
+ {children}
908
+ <span className="sr-only">{label || tooltip}</span>
909
+ </Button>
910
+ );
911
+
912
+ if (tooltip) {
913
+ return (
914
+ <TooltipProvider>
915
+ <Tooltip>
916
+ <TooltipTrigger asChild>{button}</TooltipTrigger>
917
+ <TooltipContent>
918
+ <p>{tooltip}</p>
919
+ </TooltipContent>
920
+ </Tooltip>
921
+ </TooltipProvider>
922
+ );
923
+ }
924
+
925
+ return button;
926
+ };
927
+
928
+ // ===================================
929
+ // BRANCH COMPONENTS
930
+ // ===================================
931
+
932
+ interface BranchContextType {
933
+ currentBranch: number;
934
+ totalBranches: number;
935
+ goToPrevious: () => void;
936
+ goToNext: () => void;
937
+ branches: React.ReactElement[];
938
+ setBranches: (branches: React.ReactElement[]) => void;
939
+ }
940
+
941
+ const BranchContext = createContext<BranchContextType | null>(null);
942
+
943
+ const useBranch = () => {
944
+ const context = useContext(BranchContext);
945
+
946
+ if (!context) {
947
+ throw new Error("Branch components must be used within Branch");
948
+ }
949
+
950
+ return context;
951
+ };
952
+
953
+ type BranchProps = HTMLAttributes<HTMLDivElement> & {
954
+ defaultBranch?: number;
955
+ onBranchChange?: (branchIndex: number) => void;
956
+ };
957
+
958
+ const Branch = ({
959
+ defaultBranch = 0,
960
+ onBranchChange,
961
+ className,
962
+ ...props
963
+ }: BranchProps) => {
964
+ const [currentBranch, setCurrentBranch] = useState(defaultBranch);
965
+ const [branches, setBranches] = useState<React.ReactElement[]>([]);
966
+
967
+ const handleBranchChange = (newBranch: number) => {
968
+ setCurrentBranch(newBranch);
969
+ onBranchChange?.(newBranch);
970
+ };
971
+
972
+ const goToPrevious = () => {
973
+ const newBranch =
974
+ currentBranch > 0 ? currentBranch - 1 : branches.length - 1;
975
+ handleBranchChange(newBranch);
976
+ };
977
+
978
+ const goToNext = () => {
979
+ const newBranch =
980
+ currentBranch < branches.length - 1 ? currentBranch + 1 : 0;
981
+ handleBranchChange(newBranch);
982
+ };
983
+
984
+ const contextValue: BranchContextType = {
985
+ currentBranch,
986
+ totalBranches: branches.length,
987
+ goToPrevious,
988
+ goToNext,
989
+ branches,
990
+ setBranches,
991
+ };
992
+
993
+ return (
994
+ <BranchContext.Provider value={contextValue}>
995
+ <div
996
+ className={cn("grid w-full gap-2 [&>div]:pb-0", className)}
997
+ {...props}
998
+ />
999
+ </BranchContext.Provider>
1000
+ );
1001
+ };
1002
+
1003
+ type BranchMessagesProps = HTMLAttributes<HTMLDivElement>;
1004
+
1005
+ const BranchMessages = ({ children, ...props }: BranchMessagesProps) => {
1006
+ const { currentBranch, setBranches, branches } = useBranch();
1007
+ const childrenArray = useMemo(
1008
+ () => (Array.isArray(children) ? children : [children]),
1009
+ [children],
1010
+ );
1011
+
1012
+ // Use useEffect to update branches when they change
1013
+ useEffect(() => {
1014
+ if (branches.length !== childrenArray.length) {
1015
+ setBranches(childrenArray);
1016
+ }
1017
+ }, [childrenArray, branches, setBranches]);
1018
+
1019
+ return childrenArray.map((branch, index) => (
1020
+ <div
1021
+ className={cn(
1022
+ "grid gap-2 overflow-hidden [&>div]:pb-0",
1023
+ index === currentBranch ? "block" : "hidden",
1024
+ )}
1025
+ key={branch.key}
1026
+ {...props}
1027
+ >
1028
+ {branch}
1029
+ </div>
1030
+ ));
1031
+ };
1032
+
1033
+ type BranchSelectorProps = HTMLAttributes<HTMLDivElement> & {
1034
+ from: UIMessage["role"];
1035
+ };
1036
+
1037
+ const BranchSelector = ({ className, from, ...props }: BranchSelectorProps) => {
1038
+ const { totalBranches } = useBranch();
1039
+
1040
+ // Don't render if there's only one branch
1041
+ if (totalBranches <= 1) {
1042
+ return null;
1043
+ }
1044
+
1045
+ return (
1046
+ <div
1047
+ className={cn(
1048
+ "flex items-center gap-2 self-end px-10",
1049
+ from === "assistant" ? "justify-start" : "justify-end",
1050
+ className,
1051
+ )}
1052
+ {...props}
1053
+ />
1054
+ );
1055
+ };
1056
+
1057
+ type BranchPreviousProps = ComponentProps<typeof Button>;
1058
+
1059
+ const BranchPrevious = ({
1060
+ className,
1061
+ children,
1062
+ ...props
1063
+ }: BranchPreviousProps) => {
1064
+ const { goToPrevious, totalBranches } = useBranch();
1065
+
1066
+ return (
1067
+ <Button
1068
+ aria-label="Previous branch"
1069
+ className={cn(
1070
+ "size-7 shrink-0 rounded-full text-muted-foreground transition-colors",
1071
+ "hover:bg-accent hover:text-foreground",
1072
+ "disabled:pointer-events-none disabled:opacity-50",
1073
+ className,
1074
+ )}
1075
+ disabled={totalBranches <= 1}
1076
+ onClick={goToPrevious}
1077
+ size="icon"
1078
+ type="button"
1079
+ variant="ghost"
1080
+ {...props}
1081
+ >
1082
+ {children ?? <ChevronLeftIcon size={14} />}
1083
+ </Button>
1084
+ );
1085
+ };
1086
+
1087
+ type BranchNextProps = ComponentProps<typeof Button>;
1088
+
1089
+ const BranchNext = ({ className, children, ...props }: BranchNextProps) => {
1090
+ const { goToNext, totalBranches } = useBranch();
1091
+
1092
+ return (
1093
+ <Button
1094
+ aria-label="Next branch"
1095
+ className={cn(
1096
+ "size-7 shrink-0 rounded-full text-muted-foreground transition-colors",
1097
+ "hover:bg-accent hover:text-foreground",
1098
+ "disabled:pointer-events-none disabled:opacity-50",
1099
+ className,
1100
+ )}
1101
+ disabled={totalBranches <= 1}
1102
+ onClick={goToNext}
1103
+ size="icon"
1104
+ type="button"
1105
+ variant="ghost"
1106
+ {...props}
1107
+ >
1108
+ {children ?? <ChevronRightIcon size={14} />}
1109
+ </Button>
1110
+ );
1111
+ };
1112
+
1113
+ type BranchPageProps = HTMLAttributes<HTMLSpanElement>;
1114
+
1115
+ const BranchPage = ({ className, ...props }: BranchPageProps) => {
1116
+ const { currentBranch, totalBranches } = useBranch();
1117
+
1118
+ return (
1119
+ <span
1120
+ className={cn(
1121
+ "font-medium text-muted-foreground text-xs tabular-nums",
1122
+ className,
1123
+ )}
1124
+ {...props}
1125
+ >
1126
+ {currentBranch + 1} of {totalBranches}
1127
+ </span>
1128
+ );
1129
+ };
1130
+
1131
+ // ===================================
1132
+ // CODE BLOCK COMPONENTS
1133
+ // ===================================
1134
+
1135
+ interface CodeBlockContextType {
1136
+ code: string;
1137
+ }
1138
+
1139
+ const CodeBlockContext = createContext<CodeBlockContextType>({
1140
+ code: "",
1141
+ });
1142
+
1143
+ type CodeBlockProps = HTMLAttributes<HTMLDivElement> & {
1144
+ code: string;
1145
+ language: string;
1146
+ showLineNumbers?: boolean;
1147
+ children?: ReactNode;
1148
+ };
1149
+
1150
+ const CodeBlock = ({
1151
+ code,
1152
+ language,
1153
+ showLineNumbers = false,
1154
+ className,
1155
+ children,
1156
+ ...props
1157
+ }: CodeBlockProps) => (
1158
+ <CodeBlockContext.Provider value={{ code }}>
1159
+ <div
1160
+ className={cn(
1161
+ "relative w-full overflow-hidden rounded-md border bg-background text-foreground",
1162
+ className,
1163
+ )}
1164
+ {...props}
1165
+ >
1166
+ <div className="relative">
1167
+ <Suspense fallback={null}>
1168
+ <LazyCodeBlockContent
1169
+ code={code}
1170
+ language={language}
1171
+ showLineNumbers={showLineNumbers}
1172
+ />
1173
+ </Suspense>
1174
+ {children && (
1175
+ <div className="absolute top-2 right-2 flex items-center gap-2">
1176
+ {children}
1177
+ </div>
1178
+ )}
1179
+ </div>
1180
+ </div>
1181
+ </CodeBlockContext.Provider>
1182
+ );
1183
+
1184
+ type CodeBlockCopyButtonProps = ComponentProps<typeof Button> & {
1185
+ onCopy?: () => void;
1186
+ onError?: (error: Error) => void;
1187
+ timeout?: number;
1188
+ };
1189
+
1190
+ const CodeBlockCopyButton = ({
1191
+ onCopy,
1192
+ onError,
1193
+ timeout = 2000,
1194
+ children,
1195
+ className,
1196
+ ...props
1197
+ }: CodeBlockCopyButtonProps) => {
1198
+ const [isCopied, setIsCopied] = useState(false);
1199
+ const { code } = useContext(CodeBlockContext);
1200
+
1201
+ const copyToClipboard = async () => {
1202
+ if (typeof window === "undefined" || !navigator.clipboard.writeText) {
1203
+ onError?.(new Error("Clipboard API not available"));
1204
+ return;
1205
+ }
1206
+
1207
+ try {
1208
+ await navigator.clipboard.writeText(code);
1209
+ setIsCopied(true);
1210
+ onCopy?.();
1211
+ setTimeout(() => setIsCopied(false), timeout);
1212
+ } catch (error) {
1213
+ onError?.(error as Error);
1214
+ }
1215
+ };
1216
+
1217
+ const Icon = isCopied ? CheckIcon : CopyIcon;
1218
+
1219
+ return (
1220
+ <Button
1221
+ className={cn("shrink-0", className)}
1222
+ onClick={() => void copyToClipboard()}
1223
+ size="icon"
1224
+ variant="ghost"
1225
+ {...props}
1226
+ >
1227
+ {children ?? <Icon size={14} />}
1228
+ </Button>
1229
+ );
1230
+ };
1231
+
1232
+ // ===================================
1233
+ // LOADER COMPONENT
1234
+ // ===================================
1235
+
1236
+ interface LoaderIconProps {
1237
+ size?: number;
1238
+ }
1239
+
1240
+ const LoaderIcon = ({ size = 16 }: LoaderIconProps) => (
1241
+ <svg
1242
+ height={size}
1243
+ strokeLinejoin="round"
1244
+ style={{ color: "currentcolor" }}
1245
+ viewBox="0 0 16 16"
1246
+ width={size}
1247
+ >
1248
+ <title>Loader</title>
1249
+ <g clipPath="url(#clip0_2393_1490)">
1250
+ <path d="M8 0V4" stroke="currentColor" strokeWidth="1.5" />
1251
+ <path
1252
+ d="M8 16V12"
1253
+ opacity="0.5"
1254
+ stroke="currentColor"
1255
+ strokeWidth="1.5"
1256
+ />
1257
+ <path
1258
+ d="M3.29773 1.52783L5.64887 4.7639"
1259
+ opacity="0.9"
1260
+ stroke="currentColor"
1261
+ strokeWidth="1.5"
1262
+ />
1263
+ <path
1264
+ d="M12.7023 1.52783L10.3511 4.7639"
1265
+ opacity="0.1"
1266
+ stroke="currentColor"
1267
+ strokeWidth="1.5"
1268
+ />
1269
+ <path
1270
+ d="M12.7023 14.472L10.3511 11.236"
1271
+ opacity="0.4"
1272
+ stroke="currentColor"
1273
+ strokeWidth="1.5"
1274
+ />
1275
+ <path
1276
+ d="M3.29773 14.472L5.64887 11.236"
1277
+ opacity="0.6"
1278
+ stroke="currentColor"
1279
+ strokeWidth="1.5"
1280
+ />
1281
+ <path
1282
+ d="M15.6085 5.52783L11.8043 6.7639"
1283
+ opacity="0.2"
1284
+ stroke="currentColor"
1285
+ strokeWidth="1.5"
1286
+ />
1287
+ <path
1288
+ d="M0.391602 10.472L4.19583 9.23598"
1289
+ opacity="0.7"
1290
+ stroke="currentColor"
1291
+ strokeWidth="1.5"
1292
+ />
1293
+ <path
1294
+ d="M15.6085 10.4722L11.8043 9.2361"
1295
+ opacity="0.3"
1296
+ stroke="currentColor"
1297
+ strokeWidth="1.5"
1298
+ />
1299
+ <path
1300
+ d="M0.391602 5.52783L4.19583 6.7639"
1301
+ opacity="0.8"
1302
+ stroke="currentColor"
1303
+ strokeWidth="1.5"
1304
+ />
1305
+ </g>
1306
+ <defs>
1307
+ <clipPath id="clip0_2393_1490">
1308
+ <rect fill="white" height="16" width="16" />
1309
+ </clipPath>
1310
+ </defs>
1311
+ </svg>
1312
+ );
1313
+
1314
+ type LoaderProps = HTMLAttributes<HTMLDivElement> & {
1315
+ size?: number;
1316
+ };
1317
+
1318
+ const Loader = ({ className, size = 16, ...props }: LoaderProps) => (
1319
+ <div
1320
+ className={cn(
1321
+ "inline-flex animate-spin items-center justify-center",
1322
+ className,
1323
+ )}
1324
+ {...props}
1325
+ >
1326
+ <LoaderIcon size={size} />
1327
+ </div>
1328
+ );
1329
+
1330
+ // ===================================
1331
+ // RESPONSE COMPONENT
1332
+ // ===================================
1333
+
1334
+ type ResponseProps = ComponentProps<typeof Streamdown>;
1335
+
1336
+ const Response = memo(
1337
+ ({ className, ...props }: ResponseProps) => (
1338
+ <Streamdown
1339
+ className={cn(
1340
+ "size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
1341
+ className,
1342
+ )}
1343
+ {...props}
1344
+ />
1345
+ ),
1346
+ (prevProps, nextProps) => prevProps.children === nextProps.children,
1347
+ );
1348
+
1349
+ Response.displayName = "Response";
1350
+
1351
+ // ===================================
1352
+ // REASONING COMPONENTS
1353
+ // ===================================
1354
+
1355
+ interface ReasoningContextValue {
1356
+ isStreaming: boolean;
1357
+ isOpen: boolean;
1358
+ setIsOpen: (open: boolean) => void;
1359
+ duration: number;
1360
+ }
1361
+
1362
+ const ReasoningContext = createContext<ReasoningContextValue | null>(null);
1363
+
1364
+ const useReasoning = () => {
1365
+ const context = useContext(ReasoningContext);
1366
+ if (!context) {
1367
+ throw new Error("Reasoning components must be used within Reasoning");
1368
+ }
1369
+ return context;
1370
+ };
1371
+
1372
+ type ReasoningProps = Omit<
1373
+ ComponentProps<typeof Collapsible>,
1374
+ "onOpenChange"
1375
+ > & {
1376
+ isStreaming?: boolean;
1377
+ open?: boolean;
1378
+ defaultOpen?: boolean;
1379
+ onOpenChange?: (open: boolean) => void;
1380
+ duration?: number;
1381
+ };
1382
+
1383
+ const AUTO_CLOSE_DELAY = 1000;
1384
+ const MS_IN_S = 1000;
1385
+
1386
+ const Reasoning = memo(
1387
+ ({
1388
+ className,
1389
+ isStreaming = false,
1390
+ open,
1391
+ defaultOpen = true,
1392
+ onOpenChange,
1393
+ duration: durationProp,
1394
+ children,
1395
+ ...props
1396
+ }: ReasoningProps) => {
1397
+ const [isOpen, setIsOpen] = useControllableState({
1398
+ prop: open,
1399
+ defaultProp: defaultOpen,
1400
+ onChange: onOpenChange,
1401
+ });
1402
+ const [duration, setDuration] = useControllableState({
1403
+ prop: durationProp,
1404
+ defaultProp: 0,
1405
+ });
1406
+
1407
+ const [hasAutoClosedRef, setHasAutoClosedRef] = useState(false);
1408
+ const startTimeRef = useRef<number | null>(null);
1409
+
1410
+ // Track duration when streaming starts and ends
1411
+ useEffect(() => {
1412
+ if (isStreaming && startTimeRef.current === null) {
1413
+ startTimeRef.current = Date.now();
1414
+ } else if (!isStreaming && startTimeRef.current !== null) {
1415
+ setDuration(Math.round((Date.now() - startTimeRef.current) / MS_IN_S));
1416
+ startTimeRef.current = null;
1417
+ }
1418
+ }, [isStreaming, setDuration]);
1419
+
1420
+ // Auto-open when streaming starts, auto-close when streaming ends (once only)
1421
+ useEffect(() => {
1422
+ if (defaultOpen && !isStreaming && isOpen && !hasAutoClosedRef) {
1423
+ // Add a small delay before closing to allow user to see the content
1424
+ const timer = setTimeout(() => {
1425
+ setIsOpen(false);
1426
+ setHasAutoClosedRef(true);
1427
+ }, AUTO_CLOSE_DELAY);
1428
+
1429
+ return () => clearTimeout(timer);
1430
+ }
1431
+ }, [isStreaming, isOpen, defaultOpen, setIsOpen, hasAutoClosedRef]);
1432
+
1433
+ const handleOpenChange = (newOpen: boolean) => {
1434
+ setIsOpen(newOpen);
1435
+ };
1436
+
1437
+ return (
1438
+ <ReasoningContext.Provider
1439
+ value={{ isStreaming, isOpen, setIsOpen, duration }}
1440
+ >
1441
+ <Collapsible
1442
+ className={cn("not-prose mb-4", className)}
1443
+ onOpenChange={handleOpenChange}
1444
+ open={isOpen}
1445
+ {...props}
1446
+ >
1447
+ {children}
1448
+ </Collapsible>
1449
+ </ReasoningContext.Provider>
1450
+ );
1451
+ },
1452
+ );
1453
+
1454
+ type ReasoningTriggerProps = ComponentProps<typeof CollapsibleTrigger>;
1455
+
1456
+ const ReasoningTrigger = memo(
1457
+ ({ className, children, ...props }: ReasoningTriggerProps) => {
1458
+ const { isStreaming, isOpen, duration } = useReasoning();
1459
+
1460
+ return (
1461
+ <CollapsibleTrigger
1462
+ className={cn(
1463
+ "flex items-center gap-2 text-muted-foreground text-sm",
1464
+ className,
1465
+ )}
1466
+ {...props}
1467
+ >
1468
+ {children ?? (
1469
+ <>
1470
+ <BrainIcon className="size-4" />
1471
+ {isStreaming || duration === 0 ? (
1472
+ <p>Thinking...</p>
1473
+ ) : (
1474
+ <p>Thought for {duration} seconds</p>
1475
+ )}
1476
+ <ChevronDownIcon
1477
+ className={cn(
1478
+ "size-4 text-muted-foreground transition-transform",
1479
+ isOpen ? "rotate-180" : "rotate-0",
1480
+ )}
1481
+ />
1482
+ </>
1483
+ )}
1484
+ </CollapsibleTrigger>
1485
+ );
1486
+ },
1487
+ );
1488
+
1489
+ type ReasoningContentProps = Omit<
1490
+ ComponentProps<typeof CollapsibleContent>,
1491
+ "children"
1492
+ > & {
1493
+ children: string;
1494
+ };
1495
+
1496
+ const ReasoningContent = memo(
1497
+ ({ className, children, ...props }: ReasoningContentProps) => (
1498
+ <CollapsibleContent
1499
+ className={cn(
1500
+ "mt-4 text-sm",
1501
+ "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",
1502
+ className,
1503
+ )}
1504
+ {...props}
1505
+ >
1506
+ <Response className="grid gap-2">{children}</Response>
1507
+ </CollapsibleContent>
1508
+ ),
1509
+ );
1510
+
1511
+ Reasoning.displayName = "Reasoning";
1512
+ ReasoningTrigger.displayName = "ReasoningTrigger";
1513
+ ReasoningContent.displayName = "ReasoningContent";
1514
+
1515
+ // ===================================
1516
+ // SOURCES COMPONENTS
1517
+ // ===================================
1518
+
1519
+ type SourcesProps = ComponentPropsWithRef<"div">;
1520
+
1521
+ const Sources = ({ className, ...props }: SourcesProps) => (
1522
+ <Collapsible
1523
+ className={cn("not-prose mb-4 text-primary text-xs", className)}
1524
+ {...props}
1525
+ />
1526
+ );
1527
+
1528
+ type SourcesTriggerProps = Omit<
1529
+ ComponentProps<typeof CollapsibleTrigger>,
1530
+ "count"
1531
+ > & {
1532
+ count: number;
1533
+ };
1534
+
1535
+ const SourcesTrigger = ({ count, children, ...props }: SourcesTriggerProps) => (
1536
+ <CollapsibleTrigger className="flex items-center gap-2" {...props}>
1537
+ {children ?? (
1538
+ <>
1539
+ <p className="font-medium">Used {count} sources</p>
1540
+ <ChevronDownIcon className="h-4 w-4" />
1541
+ </>
1542
+ )}
1543
+ </CollapsibleTrigger>
1544
+ );
1545
+
1546
+ type SourcesContentProps = ComponentProps<typeof CollapsibleContent>;
1547
+
1548
+ const SourcesContent = ({ className, ...props }: SourcesContentProps) => (
1549
+ <CollapsibleContent
1550
+ className={cn(
1551
+ "mt-3 flex w-fit flex-col gap-2",
1552
+ "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",
1553
+ className,
1554
+ )}
1555
+ {...props}
1556
+ />
1557
+ );
1558
+
1559
+ type SourceProps = ComponentProps<"a">;
1560
+
1561
+ const Source = ({ href, title, children, ...props }: SourceProps) => (
1562
+ <a
1563
+ className="flex items-center gap-2"
1564
+ href={href}
1565
+ rel="noreferrer"
1566
+ target="_blank"
1567
+ {...props}
1568
+ >
1569
+ {children ?? (
1570
+ <>
1571
+ <BookIcon className="h-4 w-4" />
1572
+ <span className="block font-medium">{title}</span>
1573
+ </>
1574
+ )}
1575
+ </a>
1576
+ );
1577
+
1578
+ // ===================================
1579
+ // TASK COMPONENTS
1580
+ // ===================================
1581
+
1582
+ type TaskItemFileProps = ComponentProps<"div">;
1583
+
1584
+ const TaskItemFile = ({ children, className, ...props }: TaskItemFileProps) => (
1585
+ <div
1586
+ className={cn(
1587
+ "inline-flex items-center gap-1 rounded-md border bg-secondary px-1.5 py-0.5 text-foreground text-xs",
1588
+ className,
1589
+ )}
1590
+ {...props}
1591
+ >
1592
+ {children}
1593
+ </div>
1594
+ );
1595
+
1596
+ type TaskItemProps = ComponentProps<"div">;
1597
+
1598
+ const TaskItem = ({ children, className, ...props }: TaskItemProps) => (
1599
+ <div className={cn("text-muted-foreground text-sm", className)} {...props}>
1600
+ {children}
1601
+ </div>
1602
+ );
1603
+
1604
+ type TaskProps = ComponentProps<typeof Collapsible>;
1605
+
1606
+ const Task = ({ defaultOpen = true, className, ...props }: TaskProps) => (
1607
+ <Collapsible
1608
+ className={cn(
1609
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 data-[state=closed]:animate-out data-[state=open]:animate-in",
1610
+ className,
1611
+ )}
1612
+ defaultOpen={defaultOpen}
1613
+ {...props}
1614
+ />
1615
+ );
1616
+
1617
+ type TaskTriggerProps = ComponentProps<typeof CollapsibleTrigger> & {
1618
+ title: string;
1619
+ };
1620
+
1621
+ const TaskTrigger = ({
1622
+ children,
1623
+ className,
1624
+ title,
1625
+ ...props
1626
+ }: TaskTriggerProps) => (
1627
+ <CollapsibleTrigger asChild className={cn("group", className)} {...props}>
1628
+ {children ?? (
1629
+ <div className="flex cursor-pointer items-center gap-2 text-muted-foreground hover:text-foreground">
1630
+ <SearchIcon className="size-4" />
1631
+ <p className="text-sm">{title}</p>
1632
+ <ChevronDownIcon className="size-4 transition-transform group-data-[state=open]:rotate-180" />
1633
+ </div>
1634
+ )}
1635
+ </CollapsibleTrigger>
1636
+ );
1637
+
1638
+ type TaskContentProps = ComponentProps<typeof CollapsibleContent>;
1639
+
1640
+ const TaskContent = ({ children, className, ...props }: TaskContentProps) => (
1641
+ <CollapsibleContent
1642
+ className={cn(
1643
+ "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",
1644
+ className,
1645
+ )}
1646
+ {...props}
1647
+ >
1648
+ <div className="mt-4 space-y-2 border-muted border-l-2 pl-4">
1649
+ {children}
1650
+ </div>
1651
+ </CollapsibleContent>
1652
+ );
1653
+
1654
+ // ===================================
1655
+ // TOOL COMPONENTS
1656
+ // ===================================
1657
+
1658
+ type ToolProps = ComponentProps<typeof Collapsible>;
1659
+
1660
+ const Tool = ({ className, ...props }: ToolProps) => (
1661
+ <Collapsible
1662
+ className={cn("not-prose mb-4 w-full rounded-md border", className)}
1663
+ {...props}
1664
+ />
1665
+ );
1666
+
1667
+ interface ToolHeaderProps {
1668
+ type: ToolUIPart["type"];
1669
+ state: ToolUIPart["state"];
1670
+ className?: string;
1671
+ }
1672
+
1673
+ const getStatusBadge = (status: ToolUIPart["state"]) => {
1674
+ const labels = {
1675
+ "input-streaming": "Pending",
1676
+ "input-available": "Running",
1677
+ "approval-requested": "Awaiting approval",
1678
+ "approval-responded": "Running",
1679
+ "output-available": "Completed",
1680
+ "output-error": "Error",
1681
+ "output-denied": "Denied",
1682
+ } as const;
1683
+
1684
+ const icons = {
1685
+ "input-streaming": <CircleIcon className="size-4" />,
1686
+ "input-available": <ClockIcon className="size-4 animate-pulse" />,
1687
+ "approval-requested": <ClockIcon className="size-4" />,
1688
+ "approval-responded": <ClockIcon className="size-4 animate-pulse" />,
1689
+ "output-available": <CheckCircleIcon className="size-4 text-green-600" />,
1690
+ "output-error": <XCircleIcon className="size-4 text-red-600" />,
1691
+ "output-denied": <XCircleIcon className="size-4 text-amber-600" />,
1692
+ } as const;
1693
+
1694
+ return (
1695
+ <Badge className="gap-1.5 rounded-full text-xs" variant="secondary">
1696
+ {icons[status]}
1697
+ {labels[status]}
1698
+ </Badge>
1699
+ );
1700
+ };
1701
+
1702
+ const ToolHeader = ({ className, type, state, ...props }: ToolHeaderProps) => (
1703
+ <CollapsibleTrigger
1704
+ className={cn(
1705
+ "flex w-full items-center justify-between gap-4 p-3",
1706
+ className,
1707
+ )}
1708
+ {...props}
1709
+ >
1710
+ <div className="flex items-center gap-2">
1711
+ <WrenchIcon className="size-4 text-muted-foreground" />
1712
+ <span className="font-medium text-sm">{type}</span>
1713
+ {getStatusBadge(state)}
1714
+ </div>
1715
+ <ChevronDownIcon className="size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" />
1716
+ </CollapsibleTrigger>
1717
+ );
1718
+
1719
+ type ToolContentProps = ComponentProps<typeof CollapsibleContent>;
1720
+
1721
+ const ToolContent = ({ className, ...props }: ToolContentProps) => (
1722
+ <CollapsibleContent
1723
+ className={cn(
1724
+ "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",
1725
+ className,
1726
+ )}
1727
+ {...props}
1728
+ />
1729
+ );
1730
+
1731
+ type ToolInputProps = ComponentProps<"div"> & {
1732
+ input: ToolUIPart["input"];
1733
+ };
1734
+
1735
+ const ToolInput = ({ className, input, ...props }: ToolInputProps) => (
1736
+ <div className={cn("space-y-2 overflow-hidden p-4", className)} {...props}>
1737
+ <h4 className="font-medium text-muted-foreground text-xs uppercase tracking-wide">
1738
+ Parameters
1739
+ </h4>
1740
+ <div className="rounded-md bg-muted/50">
1741
+ <CodeBlock code={JSON.stringify(input, null, 2)} language="json" />
1742
+ </div>
1743
+ </div>
1744
+ );
1745
+
1746
+ type ToolOutputProps = ComponentProps<"div"> & {
1747
+ output: ReactNode;
1748
+ errorText: ToolUIPart["errorText"];
1749
+ };
1750
+
1751
+ const ToolOutput = ({
1752
+ className,
1753
+ output,
1754
+ errorText,
1755
+ ...props
1756
+ }: ToolOutputProps) => {
1757
+ if (!(output || errorText)) {
1758
+ return null;
1759
+ }
1760
+
1761
+ return (
1762
+ <div className={cn("space-y-2 p-4", className)} {...props}>
1763
+ <h4 className="font-medium text-muted-foreground text-xs uppercase tracking-wide">
1764
+ {errorText ? "Error" : "Result"}
1765
+ </h4>
1766
+ <div
1767
+ className={cn(
1768
+ "overflow-x-auto rounded-md text-xs [&_table]:w-full",
1769
+ errorText
1770
+ ? "bg-destructive/10 text-destructive"
1771
+ : "bg-muted/50 text-foreground",
1772
+ )}
1773
+ >
1774
+ {errorText && <div>{errorText}</div>}
1775
+ {output && <div>{output}</div>}
1776
+ </div>
1777
+ </div>
1778
+ );
1779
+ };
1780
+
1781
+ // ===================================
1782
+ // INLINE CITATION COMPONENTS
1783
+ // ===================================
1784
+
1785
+ type InlineCitationProps = ComponentProps<"span">;
1786
+
1787
+ const InlineCitation = ({ className, ...props }: InlineCitationProps) => (
1788
+ <span
1789
+ className={cn("group inline items-center gap-1", className)}
1790
+ {...props}
1791
+ />
1792
+ );
1793
+
1794
+ type InlineCitationTextProps = ComponentProps<"span">;
1795
+
1796
+ const InlineCitationText = ({
1797
+ className,
1798
+ ...props
1799
+ }: InlineCitationTextProps) => (
1800
+ <span
1801
+ className={cn("transition-colors group-hover:bg-accent", className)}
1802
+ {...props}
1803
+ />
1804
+ );
1805
+
1806
+ type InlineCitationCardProps = ComponentProps<typeof HoverCard>;
1807
+
1808
+ const InlineCitationCard = (props: InlineCitationCardProps) => (
1809
+ <HoverCard closeDelay={0} openDelay={0} {...props} />
1810
+ );
1811
+
1812
+ type InlineCitationCardTriggerProps = ComponentProps<typeof Badge> & {
1813
+ sources: string[];
1814
+ };
1815
+
1816
+ const InlineCitationCardTrigger = ({
1817
+ sources,
1818
+ className,
1819
+ ...props
1820
+ }: InlineCitationCardTriggerProps) => (
1821
+ <HoverCardTrigger asChild>
1822
+ <Badge
1823
+ className={cn("ml-1 rounded-full", className)}
1824
+ variant="secondary"
1825
+ {...props}
1826
+ >
1827
+ {sources.length ? (
1828
+ <>
1829
+ {new URL(sources[0]).hostname}{" "}
1830
+ {sources.length > 1 && `+${sources.length - 1}`}
1831
+ </>
1832
+ ) : (
1833
+ "unknown"
1834
+ )}
1835
+ </Badge>
1836
+ </HoverCardTrigger>
1837
+ );
1838
+
1839
+ type InlineCitationCardBodyProps = ComponentPropsWithRef<"div">;
1840
+
1841
+ const InlineCitationCardBody = ({
1842
+ className,
1843
+ ...props
1844
+ }: InlineCitationCardBodyProps) => (
1845
+ <HoverCardContent className={cn("relative w-80 p-0", className)} {...props} />
1846
+ );
1847
+
1848
+ const CarouselApiContext = createContext<CarouselApi | undefined>(undefined);
1849
+
1850
+ const useCarouselApi = () => {
1851
+ const context = useContext(CarouselApiContext);
1852
+ return context;
1853
+ };
1854
+
1855
+ type InlineCitationCarouselProps = ComponentProps<typeof Carousel>;
1856
+
1857
+ const InlineCitationCarousel = ({
1858
+ className,
1859
+ children,
1860
+ ...props
1861
+ }: InlineCitationCarouselProps) => {
1862
+ const [api, setApi] = useState<CarouselApi>();
1863
+
1864
+ return (
1865
+ <CarouselApiContext.Provider value={api}>
1866
+ <Carousel className={cn("w-full", className)} setApi={setApi} {...props}>
1867
+ {children}
1868
+ </Carousel>
1869
+ </CarouselApiContext.Provider>
1870
+ );
1871
+ };
1872
+
1873
+ type InlineCitationCarouselContentProps = ComponentProps<"div">;
1874
+
1875
+ const InlineCitationCarouselContent = (
1876
+ props: InlineCitationCarouselContentProps,
1877
+ ) => <CarouselContent {...props} />;
1878
+
1879
+ type InlineCitationCarouselItemProps = ComponentProps<"div">;
1880
+
1881
+ const InlineCitationCarouselItem = ({
1882
+ className,
1883
+ ...props
1884
+ }: InlineCitationCarouselItemProps) => (
1885
+ <CarouselItem
1886
+ className={cn("w-full space-y-2 p-4 pl-8", className)}
1887
+ {...props}
1888
+ />
1889
+ );
1890
+
1891
+ type InlineCitationCarouselHeaderProps = ComponentProps<"div">;
1892
+
1893
+ const InlineCitationCarouselHeader = ({
1894
+ className,
1895
+ ...props
1896
+ }: InlineCitationCarouselHeaderProps) => (
1897
+ <div
1898
+ className={cn(
1899
+ "flex items-center justify-between gap-2 rounded-t-md bg-secondary p-2",
1900
+ className,
1901
+ )}
1902
+ {...props}
1903
+ />
1904
+ );
1905
+
1906
+ type InlineCitationCarouselIndexProps = ComponentProps<"div">;
1907
+
1908
+ const InlineCitationCarouselIndex = ({
1909
+ children,
1910
+ className,
1911
+ ...props
1912
+ }: InlineCitationCarouselIndexProps) => {
1913
+ const api = useCarouselApi();
1914
+ const [current, setCurrent] = useState(0);
1915
+ const isInitializedRef = useRef(false);
1916
+
1917
+ const count = api?.scrollSnapList().length ?? 0;
1918
+
1919
+ useEffect(() => {
1920
+ if (!api) {
1921
+ return;
1922
+ }
1923
+
1924
+ const updateCurrent = () => {
1925
+ setCurrent(api.selectedScrollSnap() + 1);
1926
+ };
1927
+
1928
+ // Initialize state when API first becomes available
1929
+ if (!isInitializedRef.current) {
1930
+ updateCurrent();
1931
+ isInitializedRef.current = true;
1932
+ }
1933
+
1934
+ api.on("select", updateCurrent);
1935
+ api.on("reInit", updateCurrent);
1936
+
1937
+ return () => {
1938
+ api.off("select", updateCurrent);
1939
+ api.off("reInit", updateCurrent);
1940
+ };
1941
+ }, [api]);
1942
+
1943
+ return (
1944
+ <div
1945
+ className={cn(
1946
+ "flex flex-1 items-center justify-end px-3 py-1 text-muted-foreground text-xs",
1947
+ className,
1948
+ )}
1949
+ {...props}
1950
+ >
1951
+ {children ?? `${current}/${count}`}
1952
+ </div>
1953
+ );
1954
+ };
1955
+
1956
+ type InlineCitationCarouselPrevProps = ComponentProps<"button">;
1957
+
1958
+ const InlineCitationCarouselPrev = ({
1959
+ className,
1960
+ ...props
1961
+ }: InlineCitationCarouselPrevProps) => {
1962
+ const api = useCarouselApi();
1963
+
1964
+ const handleClick = useCallback(() => {
1965
+ if (api) {
1966
+ api.scrollPrev();
1967
+ }
1968
+ }, [api]);
1969
+
1970
+ return (
1971
+ <button
1972
+ aria-label="Previous"
1973
+ className={cn("shrink-0", className)}
1974
+ onClick={handleClick}
1975
+ type="button"
1976
+ {...props}
1977
+ >
1978
+ <ArrowLeftIcon className="size-4 text-muted-foreground" />
1979
+ </button>
1980
+ );
1981
+ };
1982
+
1983
+ type InlineCitationCarouselNextProps = ComponentProps<"button">;
1984
+
1985
+ const InlineCitationCarouselNext = ({
1986
+ className,
1987
+ ...props
1988
+ }: InlineCitationCarouselNextProps) => {
1989
+ const api = useCarouselApi();
1990
+
1991
+ const handleClick = useCallback(() => {
1992
+ if (api) {
1993
+ api.scrollNext();
1994
+ }
1995
+ }, [api]);
1996
+
1997
+ return (
1998
+ <button
1999
+ aria-label="Next"
2000
+ className={cn("shrink-0", className)}
2001
+ onClick={handleClick}
2002
+ type="button"
2003
+ {...props}
2004
+ >
2005
+ <ArrowRightIcon className="size-4 text-muted-foreground" />
2006
+ </button>
2007
+ );
2008
+ };
2009
+
2010
+ type InlineCitationSourceProps = ComponentProps<"div"> & {
2011
+ title?: string;
2012
+ url?: string;
2013
+ description?: string;
2014
+ };
2015
+
2016
+ const InlineCitationSource = ({
2017
+ title,
2018
+ url,
2019
+ description,
2020
+ className,
2021
+ children,
2022
+ ...props
2023
+ }: InlineCitationSourceProps) => (
2024
+ <div className={cn("space-y-1", className)} {...props}>
2025
+ {title && (
2026
+ <h4 className="truncate font-medium text-sm leading-tight">{title}</h4>
2027
+ )}
2028
+ {url && (
2029
+ <p className="truncate break-all text-muted-foreground text-xs">{url}</p>
2030
+ )}
2031
+ {description && (
2032
+ <p className="line-clamp-3 text-muted-foreground text-sm leading-relaxed">
2033
+ {description}
2034
+ </p>
2035
+ )}
2036
+ {children}
2037
+ </div>
2038
+ );
2039
+
2040
+ type InlineCitationQuoteProps = ComponentProps<"blockquote">;
2041
+
2042
+ const InlineCitationQuote = ({
2043
+ children,
2044
+ className,
2045
+ ...props
2046
+ }: InlineCitationQuoteProps) => (
2047
+ <blockquote
2048
+ className={cn(
2049
+ "border-muted border-l-2 pl-3 text-muted-foreground text-sm italic",
2050
+ className,
2051
+ )}
2052
+ {...props}
2053
+ >
2054
+ {children}
2055
+ </blockquote>
2056
+ );
2057
+
2058
+ // ===================================
2059
+ // MAIN CHAT COMPONENT
2060
+ // ===================================
2061
+
2062
+ interface MessageItem {
2063
+ id: string;
2064
+ role: "user" | "assistant";
2065
+ text: string;
2066
+ }
2067
+
2068
+ interface ChatComponentProps {
2069
+ className?: string;
2070
+ messages?: MessageItem[];
2071
+ status?: "submitted" | "streaming" | "ready" | "error";
2072
+ suggestions?: string[];
2073
+ inputValue?: string;
2074
+ onSuggestionClick?: (text: string) => void;
2075
+ onSubmit?: (text?: string) => void;
2076
+ onInputChange?: (text: string) => void;
2077
+ }
2078
+
2079
+ const Chat = ({
2080
+ className,
2081
+ messages,
2082
+ status,
2083
+ suggestions,
2084
+ inputValue,
2085
+ onSuggestionClick,
2086
+ onSubmit,
2087
+ onInputChange,
2088
+ }: ChatComponentProps) => {
2089
+ const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
2090
+ event.preventDefault();
2091
+ event.stopPropagation();
2092
+ void onSubmit?.(inputValue);
2093
+ };
2094
+
2095
+ const handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
2096
+ const value = event.target.value;
2097
+ void onInputChange?.(value);
2098
+ };
2099
+
2100
+ return (
2101
+ <div className={cn("flex flex-col", className)}>
2102
+ <Conversation className="h-full">
2103
+ <ConversationContent>
2104
+ {messages?.map((message: MessageItem) => (
2105
+ <div key={message.id}>
2106
+ <Message from={message.role} key={message.id}>
2107
+ <MessageContent>{message.text}</MessageContent>
2108
+ </Message>
2109
+ </div>
2110
+ ))}
2111
+ </ConversationContent>
2112
+ <ConversationScrollButton />
2113
+ </Conversation>
2114
+ <Suggestions>
2115
+ {suggestions?.map((suggestion: string) => (
2116
+ <Suggestion
2117
+ key={suggestion}
2118
+ onClick={onSuggestionClick}
2119
+ suggestion={suggestion}
2120
+ />
2121
+ ))}
2122
+ </Suggestions>
2123
+ <PromptInput onSubmit={handleSubmit} className="mt-4">
2124
+ <PromptInputTextarea onChange={handleInputChange} value={inputValue} />
2125
+ <PromptInputToolbar>
2126
+ <PromptInputTools></PromptInputTools>
2127
+ <PromptInputSubmit disabled={!inputValue} status={status} />
2128
+ </PromptInputToolbar>
2129
+ </PromptInput>
2130
+ </div>
2131
+ );
2132
+ };
2133
+
2134
+ // Properties Definition
2135
+ const propertiesDefinition: PropertiesPanelDefinition<ChatComponentProps> = {
2136
+ general: Section.category(PropsCategory.Content).children({
2137
+ inputValue: Prop.string().propertiesPanel({
2138
+ label: "Input value",
2139
+ controlType: "INPUT_TEXT",
2140
+ description: "The controlled value of the chat input",
2141
+ isRemovable: true,
2142
+ visibility: "SHOW_NAME",
2143
+ }),
2144
+ messages: Prop.array<MessageItem>()
2145
+ .propertiesPanel({
2146
+ label: "Messages",
2147
+ controlType: "FUNCTION_CODE_EDITOR",
2148
+ description: "Array of messages to display in the chat",
2149
+ })
2150
+ .docs({
2151
+ description: "Array of messages to display in the chat",
2152
+ }),
2153
+ suggestions: Prop.array<string>()
2154
+ .propertiesPanel({
2155
+ label: "Suggestions",
2156
+ controlType: "FUNCTION_CODE_EDITOR",
2157
+ description: "Array of suggestions to display in the chat",
2158
+ })
2159
+ .docs({
2160
+ description: "Array of suggestions to display in the chat",
2161
+ }),
2162
+ status: Prop.string<
2163
+ "submitted" | "streaming" | "ready" | "error"
2164
+ >().propertiesPanel({
2165
+ label: "Status",
2166
+ controlType: "DROP_DOWN",
2167
+ options: [
2168
+ { label: "Submitted", value: "submitted" },
2169
+ { label: "Streaming", value: "streaming" },
2170
+ { label: "Ready", value: "ready" },
2171
+ { label: "Error", value: "error" },
2172
+ ],
2173
+ }),
2174
+ }),
2175
+ events: Section.category(PropsCategory.EventHandlers).children({
2176
+ onSubmit: Prop.eventHandler().propertiesPanel({
2177
+ label: "onSubmit",
2178
+ description: "Triggered when the user submits a message",
2179
+ computedArgs: [
2180
+ {
2181
+ name: "text",
2182
+ type: "string",
2183
+ description: "The message to be submitted",
2184
+ },
2185
+ ],
2186
+ }),
2187
+ onInputChange: Prop.eventHandler().propertiesPanel({
2188
+ label: "onInputChange",
2189
+ description: "Triggered when the user changes the input",
2190
+ computedArgs: [
2191
+ {
2192
+ name: "text",
2193
+ type: "string",
2194
+ description: "The input value",
2195
+ },
2196
+ ],
2197
+ }),
2198
+ onSuggestionClick: Prop.eventHandler().propertiesPanel({
2199
+ label: "onSuggestionClick",
2200
+ description: "Triggered when the user clicks a suggestion",
2201
+ computedArgs: [
2202
+ {
2203
+ name: "text",
2204
+ type: "string",
2205
+ description: "The suggestion text",
2206
+ },
2207
+ ],
2208
+ }),
2209
+ }),
2210
+ };
2211
+
2212
+ // Editor Configuration
2213
+ const editorConfig: EditorConfig = {
2214
+ icon: "custom", // TODO: add icon
2215
+ description: "A chat component",
2216
+ };
2217
+
2218
+ // Registration
2219
+ registerComponent(Chat, propertiesDefinition).editorConfig(editorConfig);
2220
+
2221
+ export {
2222
+ Chat,
2223
+ Conversation,
2224
+ ConversationContent,
2225
+ ConversationScrollButton,
2226
+ Message,
2227
+ MessageContent,
2228
+ MessageAvatar,
2229
+ PromptInput,
2230
+ PromptInputTextarea,
2231
+ PromptInputToolbar,
2232
+ PromptInputTools,
2233
+ PromptInputButton,
2234
+ PromptInputSubmit,
2235
+ PromptInputModelSelect,
2236
+ PromptInputModelSelectTrigger,
2237
+ PromptInputModelSelectContent,
2238
+ PromptInputModelSelectItem,
2239
+ PromptInputModelSelectValue,
2240
+ Suggestions,
2241
+ Suggestion,
2242
+ Actions,
2243
+ Action,
2244
+ Branch,
2245
+ BranchMessages,
2246
+ BranchSelector,
2247
+ BranchPrevious,
2248
+ BranchNext,
2249
+ BranchPage,
2250
+ Carousel,
2251
+ CarouselContent,
2252
+ CarouselItem,
2253
+ CarouselPrevious,
2254
+ CarouselNext,
2255
+ CodeBlock,
2256
+ CodeBlockCopyButton,
2257
+ Collapsible,
2258
+ CollapsibleTrigger,
2259
+ CollapsibleContent,
2260
+ HoverCard,
2261
+ HoverCardTrigger,
2262
+ HoverCardContent,
2263
+ InlineCitation,
2264
+ InlineCitationText,
2265
+ InlineCitationCard,
2266
+ InlineCitationCardTrigger,
2267
+ InlineCitationCardBody,
2268
+ InlineCitationCarousel,
2269
+ InlineCitationCarouselContent,
2270
+ InlineCitationCarouselItem,
2271
+ InlineCitationCarouselHeader,
2272
+ InlineCitationCarouselIndex,
2273
+ InlineCitationCarouselPrev,
2274
+ InlineCitationCarouselNext,
2275
+ InlineCitationSource,
2276
+ InlineCitationQuote,
2277
+ Loader,
2278
+ Reasoning,
2279
+ ReasoningTrigger,
2280
+ ReasoningContent,
2281
+ Response,
2282
+ ScrollArea,
2283
+ ScrollBar,
2284
+ Sources,
2285
+ SourcesTrigger,
2286
+ SourcesContent,
2287
+ Source,
2288
+ Task,
2289
+ TaskTrigger,
2290
+ TaskContent,
2291
+ TaskItem,
2292
+ TaskItemFile,
2293
+ Tool,
2294
+ ToolHeader,
2295
+ ToolContent,
2296
+ ToolInput,
2297
+ ToolOutput,
2298
+ Tooltip,
2299
+ TooltipTrigger,
2300
+ TooltipContent,
2301
+ TooltipProvider,
2302
+ type CarouselApi,
2303
+ };