@kitn.ai/ui 0.28.0 → 0.30.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 (615) hide show
  1. package/README.md +11 -7
  2. package/dist/{Icon-DObhsRtm.js → Icon-BzBET3E-.js} +1 -1
  3. package/dist/{action-icons-CcgNN2oT.js → action-icons-DaW2pU6m.js} +1 -1
  4. package/dist/agent-tooling/construct/public.d.ts +15 -0
  5. package/dist/agent-tooling/construct/schema.d.ts +111 -0
  6. package/dist/arrow-down-D783iMJj.js +1 -0
  7. package/dist/arrow-left-0VLM5kyg.js +1 -0
  8. package/dist/artifact-DGjzHYUT.js +1 -0
  9. package/dist/{attachments-Qr4kg-2b.js → attachments-YvXHlg88.js} +1 -1
  10. package/dist/{audio-visualizer-DToYdfSc.js → audio-visualizer-9lz5IHsL.js} +1 -1
  11. package/dist/{badge-CdEu_jn2.js → badge-Dh_vp8A5.js} +1 -1
  12. package/dist/{bell-DQAAOpDz.js → bell-CT7_WUwS.js} +1 -1
  13. package/dist/{button-DkuOnGLy.js → button-C_3te6fm.js} +1 -1
  14. package/dist/{card-renderer-Jx70m6_l.js → card-renderer-DZVaGH2e.js} +1 -1
  15. package/dist/check-CiEOVnEN.js +1 -0
  16. package/dist/{checkbox-D7iRB3nL.js → checkbox-Bu2T2e0U.js} +1 -1
  17. package/dist/{checkbox-group-B2_rpoPM.js → checkbox-group-BiryEXPQ.js} +1 -1
  18. package/dist/chevron-down-CSobuZRG.js +1 -0
  19. package/dist/chevron-right-DR9ZAP-2.js +1 -0
  20. package/dist/{choice-card-m0BYqqOK.js → choice-card-CM6IjkmL.js} +1 -1
  21. package/dist/circle-BC66EYF7.js +1 -0
  22. package/dist/circle-check-BqmahW0O.js +1 -0
  23. package/dist/{circle-x-BPG0iPst.js → circle-x-Bk-dA5Wf.js} +1 -1
  24. package/dist/{code-block-ClMLKb7C.js → code-block-B26t-Q7q.js} +1 -1
  25. package/dist/{collapsible-B4DlWicL.js → collapsible-Bhc636Cf.js} +1 -1
  26. package/dist/components/builder-composer-triggers.d.ts +62 -0
  27. package/dist/components/builder-layout.d.ts +54 -0
  28. package/dist/components/builder-message-actions.d.ts +72 -0
  29. package/dist/components/builder-panel.d.ts +189 -0
  30. package/dist/components/builder-preview.d.ts +11 -0
  31. package/dist/components/builder-shell-controls.d.ts +69 -0
  32. package/dist/components/builder-skeleton.d.ts +58 -0
  33. package/dist/components/builder-start.d.ts +75 -0
  34. package/dist/components/builder-workspace-variants.d.ts +23 -0
  35. package/dist/components/captions.d.ts +66 -0
  36. package/dist/{composer-sQ0HcvyG.js → composer-DMI85B6j.js} +1 -1
  37. package/dist/{confirm-card-rQWDQsnC.js → confirm-card-B0YIAwXp.js} +1 -1
  38. package/dist/construct-cli.es.js +3 -3
  39. package/dist/construct.d.ts +5 -0
  40. package/dist/construct.js +327 -0
  41. package/dist/{context-0kg4ZX1J.js → context-DWgfhqWp.js} +1 -1
  42. package/dist/controllable-BagRpyHv.js +1 -0
  43. package/dist/{conversation-item-BxwQLaFJ.js → conversation-item-BsOsVGmT.js} +1 -1
  44. package/dist/{conversation-list-BCfGN1JU.js → conversation-list-aX3Vtc7L.js} +1 -1
  45. package/dist/{copy-n9u9rqpi.js → copy-BmEwsNhJ.js} +1 -1
  46. package/dist/core-C8fzo39E.js +1 -12
  47. package/dist/{create-tween-uPkArjIG.js → create-tween-CNOAU3Fx.js} +1 -1
  48. package/dist/{create-tween-C-q-JCM-.js → create-tween-WfqiENls.js} +1 -1
  49. package/dist/{create-tween-CRrJXxBd.js → create-tween-wlFtW9Kh.js} +1 -1
  50. package/dist/{create-tween-DZ3RRDHD.js → create-tween-zt79ba32.js} +1 -1
  51. package/dist/{default-input-CaMrJkgH.js → default-input-DMV5Eaze.js} +1 -1
  52. package/dist/define-CI0y3eE4.js +1 -0
  53. package/dist/define.js +40 -40
  54. package/dist/define.server.js +45 -45
  55. package/dist/{disclosure-WUImBbDv.js → disclosure-NnACBxsC.js} +1 -1
  56. package/dist/{dropdown-wZVeJOMd.js → dropdown-DT7G0RGR.js} +1 -1
  57. package/dist/elements/agent-card.js +1 -1
  58. package/dist/elements/artifact.js +1 -1
  59. package/dist/elements/attachments.js +1 -1
  60. package/dist/elements/audio-visualizer.js +1 -1
  61. package/dist/elements/avatar.js +1 -1
  62. package/dist/elements/badge.js +1 -1
  63. package/dist/elements/button.js +1 -1
  64. package/dist/elements/card.js +1 -1
  65. package/dist/elements/cards.js +1 -1
  66. package/dist/elements/chain-of-thought.js +1 -1
  67. package/dist/elements/chat-scope-picker.js +1 -1
  68. package/dist/elements/chat-workspace.js +1 -1
  69. package/dist/elements/chat.js +1 -1
  70. package/dist/elements/checkbox-group.js +1 -1
  71. package/dist/elements/checkbox.js +1 -1
  72. package/dist/elements/checkpoint.js +1 -1
  73. package/dist/elements/choice.js +1 -1
  74. package/dist/elements/coachmark.js +1 -1
  75. package/dist/elements/code-block.js +1 -1
  76. package/dist/elements/command.js +1 -1
  77. package/dist/elements/compare.js +1 -1
  78. package/dist/elements/composer.js +1 -1
  79. package/dist/elements/confirm-card.js +1 -1
  80. package/dist/elements/context-meter.js +1 -1
  81. package/dist/elements/conversation-item.js +1 -1
  82. package/dist/elements/conversation-list.js +1 -1
  83. package/dist/elements/dialog.js +1 -1
  84. package/dist/elements/dock.js +1 -1
  85. package/dist/elements/dropdown.js +1 -1
  86. package/dist/elements/editable-label.js +1 -1
  87. package/dist/elements/embed.js +1 -1
  88. package/dist/elements/empty.js +1 -1
  89. package/dist/elements/feedback-bar.js +1 -1
  90. package/dist/elements/file-tree.js +1 -1
  91. package/dist/elements/file-upload.js +1 -1
  92. package/dist/elements/form.js +1 -1
  93. package/dist/elements/hover-card.js +1 -1
  94. package/dist/elements/icon.js +1 -1
  95. package/dist/elements/image.js +1 -1
  96. package/dist/elements/input.js +1 -1
  97. package/dist/elements/kbd.js +1 -1
  98. package/dist/elements/link-preview.js +1 -1
  99. package/dist/elements/loader.js +1 -1
  100. package/dist/elements/markdown.js +1 -1
  101. package/dist/elements/menu.js +1 -1
  102. package/dist/elements/message-skills.js +1 -1
  103. package/dist/elements/message.js +1 -1
  104. package/dist/elements/model-switcher.js +1 -1
  105. package/dist/elements/nav.js +1 -1
  106. package/dist/elements/notice.js +1 -1
  107. package/dist/elements/pane-grid.js +1 -1
  108. package/dist/elements/pane-group.js +1 -1
  109. package/dist/elements/pane.js +1 -1
  110. package/dist/elements/popover.js +1 -1
  111. package/dist/elements/progress-bar.js +1 -1
  112. package/dist/elements/prompt-dock.js +1 -1
  113. package/dist/elements/prompt-input.js +1 -1
  114. package/dist/elements/prompt-suggestions.js +1 -1
  115. package/dist/elements/radio-group.js +1 -1
  116. package/dist/elements/reasoning.js +1 -1
  117. package/dist/elements/remote.js +1 -1
  118. package/dist/elements/resizable.js +1 -1
  119. package/dist/elements/response-stream.js +1 -1
  120. package/dist/elements/screen.js +1 -1
  121. package/dist/elements/scroll-area.js +1 -1
  122. package/dist/elements/scroll-button.js +1 -1
  123. package/dist/elements/search.js +1 -1
  124. package/dist/elements/segmented.js +1 -1
  125. package/dist/elements/select.js +1 -1
  126. package/dist/elements/separator.js +1 -1
  127. package/dist/elements/setting-item.js +1 -1
  128. package/dist/elements/settings-group.js +1 -1
  129. package/dist/elements/skeleton.js +1 -1
  130. package/dist/elements/slider.js +1 -1
  131. package/dist/elements/source.js +1 -1
  132. package/dist/elements/status.js +1 -1
  133. package/dist/elements/switch.js +1 -1
  134. package/dist/elements/tabs.js +1 -1
  135. package/dist/elements/tasks.js +1 -1
  136. package/dist/elements/text-shimmer.js +1 -1
  137. package/dist/elements/thinking-bar.js +1 -1
  138. package/dist/elements/thread.js +1 -1
  139. package/dist/elements/toast.js +1 -1
  140. package/dist/elements/tool.js +1 -1
  141. package/dist/elements/tooltip.js +1 -1
  142. package/dist/elements/voice-input.js +1 -1
  143. package/dist/elements/voice-output.js +1 -1
  144. package/dist/{ellipsis-CbOpJnU3.js → ellipsis-6pJ7SxYT.js} +1 -1
  145. package/dist/{embed-CrfjkbUG.js → embed-BMje-nxj.js} +1 -1
  146. package/dist/engine-javascript-C1x7zo1_.js +1 -141
  147. package/dist/{external-link-ByXAwBBQ.js → external-link-Beh9DKeR.js} +1 -1
  148. package/dist/{file-text-DMib2qwt.js → file-text-D1GPfZ8Q.js} +1 -1
  149. package/dist/{file-tree-CJqM2aP7.js → file-tree-Dwj2lqg-.js} +1 -1
  150. package/dist/{folder-_BAb929C.js → folder-b6D8x1DY.js} +1 -1
  151. package/dist/{form-DSZgZQZk.js → form-DWgdxDXu.js} +1 -1
  152. package/dist/{hover-card-BQbul9eq.js → hover-card-CWRkqm40.js} +1 -1
  153. package/dist/{icon-CdcfRhYI.js → icon-CL0jdhsf.js} +1 -1
  154. package/dist/index.js +1741 -1725
  155. package/dist/index.server.js +1582 -1566
  156. package/dist/{info-DsFjGuI_.js → info-0cOUherQ.js} +1 -1
  157. package/dist/{input-DKbmkMos.js → input-BH6Ru91Q.js} +1 -1
  158. package/dist/kai.es.js +1 -1
  159. package/dist/{kbd-PvdGhX4s.js → kbd-DRAnVtNX.js} +1 -1
  160. package/dist/{link-zF8PzWfF.js → link-Dlr0vssB.js} +1 -1
  161. package/dist/{link-preview-DbM1866N.js → link-preview-DODgRyV9.js} +1 -1
  162. package/dist/loader-KvJB6NrT.js +1 -0
  163. package/dist/{markdown-LMvmAyBk.js → markdown-DX9tuJVj.js} +1 -1
  164. package/dist/mcp.es.js +9 -5
  165. package/dist/{message-BYZECyek.js → message-BqQ7Ot5q.js} +1 -1
  166. package/dist/{message-BSsgvHvf.js → message-DkaGfBd8.js} +1 -1
  167. package/dist/message-circle-BPpp5QKv.js +1 -0
  168. package/dist/message-square-BLbsd9BJ.js +1 -0
  169. package/dist/{minimize-2-BQRoBV1V.js → minimize-2-CyOHJwcN.js} +1 -1
  170. package/dist/{model-switcher-CMpCOYcB.js → model-switcher-0hrKDiK2.js} +1 -1
  171. package/dist/{overlay-Cb-MkyDa.js → overlay-DBMFXie6.js} +1 -1
  172. package/dist/{panel-right-i8warFxT.js → panel-right-t8SWJL6e.js} +1 -1
  173. package/dist/{paperclip-ByY3UVO6.js → paperclip-CdzuOjbU.js} +1 -1
  174. package/dist/play-BXy1u7rW.js +1 -0
  175. package/dist/primitives/use-auto-resize.d.ts +11 -0
  176. package/dist/{progress-bar-jVAHvMUf.js → progress-bar-CiBtxMWT.js} +1 -1
  177. package/dist/{prompt-suggestion-CD-qtNgC.js → prompt-suggestion-I_DHP21i.js} +1 -1
  178. package/dist/{radio-BsoBMhkF.js → radio-C_p3n39l.js} +1 -1
  179. package/dist/{reasoning-4kBPtlTx.js → reasoning-BDwy_tIe.js} +1 -1
  180. package/dist/register-impl-DvEnhIxx.js +424 -0
  181. package/dist/{resizable-uPmY9VY-.js → resizable-SYC-fStM.js} +1 -1
  182. package/dist/{rotate-ccw-B2xn93py.js → rotate-ccw-B1nwmwuY.js} +1 -1
  183. package/dist/{rotate-cw-CMVLoCyH.js → rotate-cw-CLAnBcm1.js} +1 -1
  184. package/dist/{scroll-area-BqLUo8ZZ.js → scroll-area-zRyXoLhI.js} +1 -1
  185. package/dist/{scroll-button-DslXiJyL.js → scroll-button-jzrbYCG9.js} +1 -1
  186. package/dist/{select-2cLRtPGT.js → select-DM-0nEe0.js} +1 -1
  187. package/dist/{separator-BWQtNJcM.js → separator-BToOOoOt.js} +1 -1
  188. package/dist/{settings-BBR63jLg.js → settings-PaGo_S4U.js} +1 -1
  189. package/dist/{settings-group-B2ciy-Iw.js → settings-group-BFXGIfXq.js} +1 -1
  190. package/dist/{skeleton-CkHI-HgC.js → skeleton-DYpmFnnm.js} +1 -1
  191. package/dist/{slider-DDR9U-i0.js → slider-ebutAmkQ.js} +1 -1
  192. package/dist/{solid-DruVOXnf.js → solid-15v_3WVL.js} +3563 -3412
  193. package/dist/{solid-BzCFdL25.js → solid-5P-otgdi.js} +4502 -4296
  194. package/dist/solid.d.ts +6 -0
  195. package/dist/solid.js +259 -254
  196. package/dist/solid.server.js +259 -254
  197. package/dist/{source-GEnFF528.js → source-c1gpRl9h.js} +1 -1
  198. package/dist/{star-CilHq8GP.js → star-pcV_3LqF.js} +1 -1
  199. package/dist/{store-Ciyk6eZG.js → store-CSgbFFCg.js} +1 -1
  200. package/dist/{switch-KkeQIbuH.js → switch-Bh2OdLV2.js} +1 -1
  201. package/dist/{tasks-card-BrN4bggJ.js → tasks-card-CbqQAn2S.js} +1 -1
  202. package/dist/text-shimmer-BSzgEnDH.js +1 -0
  203. package/dist/textarea-DrYNt_0z.js +1 -0
  204. package/dist/theme.tokens.css +22 -21
  205. package/dist/{thumbs-up-CsT9Wzb9.js → thumbs-up-BL3-NenK.js} +1 -1
  206. package/dist/{toast-store-tgK6MuMv.js → toast-store-DkOlYczt.js} +1 -1
  207. package/dist/{tool-DzUjIBT8.js → tool-CeIWUVUe.js} +1 -1
  208. package/dist/{tooltip-Bkkg_4t0.js → tooltip-GA-nmg06.js} +1 -1
  209. package/dist/{trash-2-jBKxjGGQ.js → trash-2-CT66QWlm.js} +1 -1
  210. package/dist/{triangle-alert-DlQ68ppf.js → triangle-alert-CeHLWxhD.js} +1 -1
  211. package/dist/ui/color-field.d.ts +48 -0
  212. package/dist/ui/textarea.d.ts +4 -0
  213. package/dist/ui/toggle-chip.d.ts +40 -0
  214. package/dist/{upload-TcAHXv9W.js → upload-9Csb0F0J.js} +1 -1
  215. package/dist/{use-card-resolution-DaZqAdWf.js → use-card-resolution-Zg0a08Z-.js} +1 -1
  216. package/dist/{variant-aurora-DbW_OWL2.js → variant-aurora-4VBQHIKV.js} +1 -1
  217. package/dist/{variant-aurora-CNmfHhcx.js → variant-aurora-DBeCAQNk.js} +2 -2
  218. package/dist/{variant-aurora-D6GsdTPA.js → variant-aurora-FzHVXHby.js} +2 -2
  219. package/dist/{variant-aurora-BhLuYxJR.js → variant-aurora-LE3fqxgw.js} +1 -1
  220. package/dist/{variant-custom-BvYHR62b.js → variant-custom-AFRGcOBS.js} +1 -1
  221. package/dist/{variant-custom-DV2x254s.js → variant-custom-BQkNuPpE.js} +2 -2
  222. package/dist/{variant-custom-BRvaNHSi.js → variant-custom-DI5R0rln.js} +1 -1
  223. package/dist/{variant-custom-DMTrEO5w.js → variant-custom-WWnrrRHS.js} +2 -2
  224. package/dist/{variant-wave-CyBueXj9.js → variant-wave-DUCbH5oI.js} +2 -2
  225. package/dist/{variant-wave-BNMGrDfj.js → variant-wave-DuQV7DhQ.js} +2 -2
  226. package/dist/{variant-wave-BpDd8t3Z.js → variant-wave-nSI2sfII.js} +1 -1
  227. package/dist/{variant-wave-sp-qwsdI.js → variant-wave-wTP5v_jU.js} +1 -1
  228. package/dist/x-eiO9V6J6.js +1 -0
  229. package/{src/elements/styles.css → kit-base.css} +27 -44
  230. package/package.json +32 -17
  231. package/solid.css +33 -0
  232. package/theme.css +39 -23
  233. package/bin/route.test.js +0 -58
  234. package/dist/arrow-down-CjRU3JgV.js +0 -1
  235. package/dist/arrow-left-Bnpb1UEW.js +0 -1
  236. package/dist/artifact-Bwt7OgcR.js +0 -1
  237. package/dist/check-njkVdZu2.js +0 -1
  238. package/dist/chevron-down-B72s6PXR.js +0 -1
  239. package/dist/chevron-right-BatuHzUm.js +0 -1
  240. package/dist/circle-check-B62pODB3.js +0 -1
  241. package/dist/circle-zx0ByzY9.js +0 -1
  242. package/dist/controllable-CnGpMF6r.js +0 -1
  243. package/dist/define-By-uL588.js +0 -1
  244. package/dist/loader-BM4CEz4G.js +0 -1
  245. package/dist/message-circle-DruwObfX.js +0 -1
  246. package/dist/message-square-BG6q6mlm.js +0 -1
  247. package/dist/play-BvKKq3fX.js +0 -1
  248. package/dist/register-impl-B1hLkrI8.js +0 -424
  249. package/dist/text-shimmer-Dcj1MHuq.js +0 -1
  250. package/dist/textarea-Dpvbngbg.js +0 -1
  251. package/dist/x-Z5UntkIJ.js +0 -1
  252. package/src/agent-tooling/README.md +0 -192
  253. package/src/agent-tooling/archetypes.ts +0 -205
  254. package/src/agent-tooling/catalog/README.md +0 -676
  255. package/src/agent-tooling/catalog/catalog-types.ts +0 -231
  256. package/src/agent-tooling/catalog/fabrications.ts +0 -96
  257. package/src/agent-tooling/catalog/invariants.ts +0 -284
  258. package/src/agent-tooling/catalog/labs-titles.ts +0 -114
  259. package/src/agent-tooling/catalog/scenarios.ts +0 -87
  260. package/src/agent-tooling/catalog/surfaces.ts +0 -347
  261. package/src/agent-tooling/construct/cli-entry.ts +0 -8
  262. package/src/agent-tooling/construct/cli.ts +0 -147
  263. package/src/agent-tooling/construct/codegen.ts +0 -1635
  264. package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
  265. package/src/agent-tooling/construct/dev.ts +0 -148
  266. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
  267. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
  268. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
  269. package/src/agent-tooling/construct/schema.ts +0 -452
  270. package/src/agent-tooling/integrations/anthropic.ts +0 -442
  271. package/src/agent-tooling/integrations/cloudflare.ts +0 -218
  272. package/src/agent-tooling/integrations/langgraph.ts +0 -133
  273. package/src/agent-tooling/integrations/mastra.ts +0 -182
  274. package/src/agent-tooling/integrations/mock.ts +0 -148
  275. package/src/agent-tooling/integrations/ollama.ts +0 -97
  276. package/src/agent-tooling/integrations/openai.ts +0 -95
  277. package/src/agent-tooling/integrations/openrouter.ts +0 -82
  278. package/src/agent-tooling/integrations/pi.ts +0 -176
  279. package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
  280. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
  281. package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
  282. package/src/agent-tooling/mcp/manifest.ts +0 -422
  283. package/src/agent-tooling/mcp/server.ts +0 -116
  284. package/src/agent-tooling/mcp/stdio.ts +0 -18
  285. package/src/agent-tooling/mcp/tools/construct.ts +0 -130
  286. package/src/agent-tooling/mcp/tools/debug.ts +0 -621
  287. package/src/agent-tooling/mcp/tools/reference.ts +0 -980
  288. package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
  289. package/src/agent-tooling/mcp/tools/theme.ts +0 -456
  290. package/src/agent-tooling/mcp/tools/types.ts +0 -14
  291. package/src/agent-tooling/mcp/validate-args.ts +0 -141
  292. package/src/agent-tooling/recipes/composed-thread.ts +0 -714
  293. package/src/agent-tooling/recipes/index.ts +0 -22
  294. package/src/agent-tooling/recipes/types.ts +0 -32
  295. package/src/agent-tooling/registry.ts +0 -132
  296. package/src/agent-tooling/route-emit.ts +0 -305
  297. package/src/agent-tooling/types.ts +0 -390
  298. package/src/components/artifact-card.tsx +0 -120
  299. package/src/components/artifact.tsx +0 -914
  300. package/src/components/attachment-types.ts +0 -66
  301. package/src/components/attachments.tsx +0 -536
  302. package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
  303. package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
  304. package/src/components/audio-visualizer/fit-scale.ts +0 -112
  305. package/src/components/audio-visualizer/index.tsx +0 -528
  306. package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
  307. package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
  308. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
  309. package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
  310. package/src/components/audio-visualizer/sizes.ts +0 -54
  311. package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
  312. package/src/components/audio-visualizer/variant-bar.tsx +0 -175
  313. package/src/components/audio-visualizer/variant-custom.tsx +0 -344
  314. package/src/components/audio-visualizer/variant-grid.tsx +0 -175
  315. package/src/components/audio-visualizer/variant-radial.tsx +0 -163
  316. package/src/components/audio-visualizer/variant-wave.tsx +0 -130
  317. package/src/components/audio-visualizer/wave.glsl.ts +0 -130
  318. package/src/components/card-fallback.tsx +0 -60
  319. package/src/components/card-renderer.tsx +0 -220
  320. package/src/components/card.tsx +0 -212
  321. package/src/components/chain-of-thought.tsx +0 -348
  322. package/src/components/chat-container.tsx +0 -89
  323. package/src/components/chat-scope-picker.tsx +0 -57
  324. package/src/components/chat-thread.tsx +0 -1014
  325. package/src/components/checkpoint.tsx +0 -88
  326. package/src/components/choice-card.tsx +0 -743
  327. package/src/components/coachmark.tsx +0 -249
  328. package/src/components/code-block.tsx +0 -181
  329. package/src/components/composer-dom.ts +0 -159
  330. package/src/components/composer-highlight.ts +0 -242
  331. package/src/components/composer-history.ts +0 -82
  332. package/src/components/composer.tsx +0 -1075
  333. package/src/components/confirm-card.tsx +0 -402
  334. package/src/components/context.tsx +0 -377
  335. package/src/components/conversation-item.tsx +0 -241
  336. package/src/components/conversation-list.tsx +0 -429
  337. package/src/components/conversation-panel.tsx +0 -118
  338. package/src/components/dismissed-stub.tsx +0 -80
  339. package/src/components/embed.tsx +0 -200
  340. package/src/components/empty.tsx +0 -177
  341. package/src/components/feedback-bar.tsx +0 -166
  342. package/src/components/file-tree.tsx +0 -530
  343. package/src/components/file-upload.tsx +0 -167
  344. package/src/components/form-widgets.tsx +0 -525
  345. package/src/components/form.tsx +0 -1296
  346. package/src/components/home-panel.tsx +0 -159
  347. package/src/components/image.tsx +0 -65
  348. package/src/components/link-preview.tsx +0 -195
  349. package/src/components/loader.tsx +0 -367
  350. package/src/components/markdown.tsx +0 -162
  351. package/src/components/message-skills.tsx +0 -40
  352. package/src/components/message.tsx +0 -765
  353. package/src/components/model-switcher.tsx +0 -132
  354. package/src/components/prompt-input.tsx +0 -188
  355. package/src/components/prompt-suggestion.tsx +0 -150
  356. package/src/components/reasoning.tsx +0 -293
  357. package/src/components/response-compare-types.ts +0 -152
  358. package/src/components/response-compare.tsx +0 -455
  359. package/src/components/response-stream.tsx +0 -109
  360. package/src/components/screen.tsx +0 -181
  361. package/src/components/scroll-button.tsx +0 -93
  362. package/src/components/source.tsx +0 -192
  363. package/src/components/tasks-card.tsx +0 -801
  364. package/src/components/text-shimmer.tsx +0 -37
  365. package/src/components/thinking-bar.tsx +0 -50
  366. package/src/components/thread.tsx +0 -228
  367. package/src/components/toast.tsx +0 -503
  368. package/src/components/tool-classify.ts +0 -26
  369. package/src/components/tool-types.ts +0 -49
  370. package/src/components/tool.tsx +0 -190
  371. package/src/components/use-card-resolution.ts +0 -44
  372. package/src/components/voice-input.tsx +0 -222
  373. package/src/components/voice-output.tsx +0 -242
  374. package/src/components/widget-tab-bar.tsx +0 -73
  375. package/src/components/workspace-shell.tsx +0 -285
  376. package/src/diagnostics/hook.ts +0 -352
  377. package/src/diagnostics/index.ts +0 -82
  378. package/src/diagnostics/report-request.ts +0 -296
  379. package/src/elements/agent-card.tsx +0 -67
  380. package/src/elements/artifact.tsx +0 -194
  381. package/src/elements/attachments.tsx +0 -140
  382. package/src/elements/audio-visualizer.tsx +0 -227
  383. package/src/elements/autoloader.ts +0 -89
  384. package/src/elements/avatar.tsx +0 -33
  385. package/src/elements/badge.tsx +0 -32
  386. package/src/elements/button.tsx +0 -149
  387. package/src/elements/card.tsx +0 -133
  388. package/src/elements/cards.tsx +0 -266
  389. package/src/elements/chain-of-thought.tsx +0 -141
  390. package/src/elements/chat-scope-picker.tsx +0 -65
  391. package/src/elements/chat-types.ts +0 -102
  392. package/src/elements/chat-workspace.tsx +0 -188
  393. package/src/elements/chat.tsx +0 -304
  394. package/src/elements/checkbox-group.tsx +0 -164
  395. package/src/elements/checkbox.tsx +0 -134
  396. package/src/elements/checkpoint.tsx +0 -47
  397. package/src/elements/choice.tsx +0 -100
  398. package/src/elements/coachmark.tsx +0 -90
  399. package/src/elements/code-block.tsx +0 -60
  400. package/src/elements/command.tsx +0 -197
  401. package/src/elements/compare.tsx +0 -111
  402. package/src/elements/compiled.css +0 -2
  403. package/src/elements/composer.tsx +0 -162
  404. package/src/elements/confirm-card.tsx +0 -76
  405. package/src/elements/context-meter.tsx +0 -107
  406. package/src/elements/conversation-item.tsx +0 -120
  407. package/src/elements/conversation-list.tsx +0 -203
  408. package/src/elements/css.ts +0 -5
  409. package/src/elements/default-input.tsx +0 -392
  410. package/src/elements/define-entry.ts +0 -12
  411. package/src/elements/define.tsx +0 -563
  412. package/src/elements/diagnostic-events.ts +0 -114
  413. package/src/elements/dialog.tsx +0 -145
  414. package/src/elements/disclosure.ts +0 -95
  415. package/src/elements/dock.tsx +0 -215
  416. package/src/elements/dropdown.tsx +0 -123
  417. package/src/elements/editable-label.tsx +0 -140
  418. package/src/elements/element-data-types.ts +0 -152
  419. package/src/elements/element-diagnostics.ts +0 -392
  420. package/src/elements/element-manifest.json +0 -354
  421. package/src/elements/element-nonscalar.json +0 -187
  422. package/src/elements/element-types.d.ts +0 -4353
  423. package/src/elements/embed.tsx +0 -35
  424. package/src/elements/empty.tsx +0 -29
  425. package/src/elements/feedback-bar.tsx +0 -66
  426. package/src/elements/file-tree.tsx +0 -62
  427. package/src/elements/file-upload.tsx +0 -44
  428. package/src/elements/form.tsx +0 -94
  429. package/src/elements/hover-card.tsx +0 -80
  430. package/src/elements/icon.tsx +0 -41
  431. package/src/elements/image.tsx +0 -32
  432. package/src/elements/input.tsx +0 -492
  433. package/src/elements/kbd.tsx +0 -45
  434. package/src/elements/link-preview.tsx +0 -34
  435. package/src/elements/loader.tsx +0 -25
  436. package/src/elements/markdown.tsx +0 -38
  437. package/src/elements/menu.tsx +0 -241
  438. package/src/elements/message-skills.tsx +0 -83
  439. package/src/elements/message.tsx +0 -361
  440. package/src/elements/model-switcher.tsx +0 -121
  441. package/src/elements/nav.tsx +0 -87
  442. package/src/elements/notice.tsx +0 -53
  443. package/src/elements/pane-grid.tsx +0 -111
  444. package/src/elements/pane-group.tsx +0 -119
  445. package/src/elements/pane.tsx +0 -129
  446. package/src/elements/popover.tsx +0 -81
  447. package/src/elements/progress-bar.tsx +0 -39
  448. package/src/elements/prompt-dock.tsx +0 -82
  449. package/src/elements/prompt-input.tsx +0 -240
  450. package/src/elements/prompt-suggestions.tsx +0 -113
  451. package/src/elements/radio-group.tsx +0 -129
  452. package/src/elements/reasoning.tsx +0 -71
  453. package/src/elements/register-impl.ts +0 -148
  454. package/src/elements/register.ts +0 -76
  455. package/src/elements/remote.tsx +0 -225
  456. package/src/elements/resizable.globals.d.ts +0 -36
  457. package/src/elements/resizable.tsx +0 -704
  458. package/src/elements/response-stream.tsx +0 -40
  459. package/src/elements/screen.tsx +0 -90
  460. package/src/elements/scroll-area.tsx +0 -33
  461. package/src/elements/scroll-button.tsx +0 -179
  462. package/src/elements/search.tsx +0 -185
  463. package/src/elements/segmented.tsx +0 -129
  464. package/src/elements/select.tsx +0 -165
  465. package/src/elements/separator.tsx +0 -36
  466. package/src/elements/setting-item.tsx +0 -50
  467. package/src/elements/settings-group.tsx +0 -37
  468. package/src/elements/skeleton.tsx +0 -45
  469. package/src/elements/slider.tsx +0 -171
  470. package/src/elements/slot-text.ts +0 -73
  471. package/src/elements/slots.ts +0 -787
  472. package/src/elements/source.tsx +0 -126
  473. package/src/elements/status.tsx +0 -42
  474. package/src/elements/switch.tsx +0 -118
  475. package/src/elements/tabs.tsx +0 -95
  476. package/src/elements/tasks.tsx +0 -103
  477. package/src/elements/text-shimmer.tsx +0 -28
  478. package/src/elements/thinking-bar.tsx +0 -43
  479. package/src/elements/thread.tsx +0 -139
  480. package/src/elements/toast.tsx +0 -106
  481. package/src/elements/tool.tsx +0 -78
  482. package/src/elements/tooltip.tsx +0 -85
  483. package/src/elements/validate-messages.ts +0 -76
  484. package/src/elements/voice-input.tsx +0 -100
  485. package/src/elements/voice-output.tsx +0 -82
  486. package/src/index.ts +0 -430
  487. package/src/primitives/audio-bands.ts +0 -174
  488. package/src/primitives/card-component-types.ts +0 -63
  489. package/src/primitives/card-contract.ts +0 -80
  490. package/src/primitives/card-data-types.ts +0 -361
  491. package/src/primitives/card-host.tsx +0 -37
  492. package/src/primitives/card-recovery.ts +0 -160
  493. package/src/primitives/card-registry.tsx +0 -78
  494. package/src/primitives/card-resolution.ts +0 -36
  495. package/src/primitives/card-routing.ts +0 -85
  496. package/src/primitives/card-schemas/artifact.schema.json +0 -92
  497. package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
  498. package/src/primitives/card-schemas/card-event.schema.json +0 -12
  499. package/src/primitives/card-schemas/choice.schema.json +0 -75
  500. package/src/primitives/card-schemas/confirm.schema.json +0 -65
  501. package/src/primitives/card-schemas/embed.schema.json +0 -63
  502. package/src/primitives/card-schemas/form.result.schema.json +0 -7
  503. package/src/primitives/card-schemas/form.schema.json +0 -53
  504. package/src/primitives/card-schemas/link.schema.json +0 -54
  505. package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
  506. package/src/primitives/card-schemas/tasks.schema.json +0 -83
  507. package/src/primitives/card-tags.ts +0 -61
  508. package/src/primitives/card-validate-cards.ts +0 -255
  509. package/src/primitives/card-validate-schemas.ts +0 -58
  510. package/src/primitives/card-validate.ts +0 -131
  511. package/src/primitives/chat-config.tsx +0 -103
  512. package/src/primitives/composer-model.ts +0 -49
  513. package/src/primitives/composer-triggers.ts +0 -35
  514. package/src/primitives/controllable.ts +0 -21
  515. package/src/primitives/conversation-store.ts +0 -248
  516. package/src/primitives/create-kai-chat.ts +0 -66
  517. package/src/primitives/create-tween.ts +0 -266
  518. package/src/primitives/embed-providers.ts +0 -254
  519. package/src/primitives/field-mask.ts +0 -256
  520. package/src/primitives/field-semantics.ts +0 -115
  521. package/src/primitives/highlighter.ts +0 -157
  522. package/src/primitives/input-mask.ts +0 -853
  523. package/src/primitives/link-preview.ts +0 -87
  524. package/src/primitives/message-feedback.ts +0 -124
  525. package/src/primitives/pdf-preview.ts +0 -121
  526. package/src/primitives/toast-store.ts +0 -338
  527. package/src/primitives/url-scheme-policy.ts +0 -70
  528. package/src/primitives/use-audio-analysis.ts +0 -340
  529. package/src/primitives/use-auto-resize.ts +0 -31
  530. package/src/primitives/use-resize-observer.ts +0 -45
  531. package/src/primitives/use-sequencer.ts +0 -72
  532. package/src/primitives/use-speech-recognition.ts +0 -146
  533. package/src/primitives/use-stick-to-bottom.ts +0 -75
  534. package/src/primitives/use-text-stream.ts +0 -143
  535. package/src/primitives/use-voice-recorder.ts +0 -62
  536. package/src/primitives/visualizer-sequences.ts +0 -350
  537. package/src/remote/host-embed.ts +0 -345
  538. package/src/remote/index.ts +0 -2
  539. package/src/remote/origin.ts +0 -30
  540. package/src/remote/provider-runtime.ts +0 -262
  541. package/src/remote/provider.ts +0 -2
  542. package/src/remote/validate.ts +0 -22
  543. package/src/remote/version.ts +0 -12
  544. package/src/remote/wire.ts +0 -48
  545. package/src/schemas/from-tool-call.ts +0 -151
  546. package/src/schemas/index.ts +0 -341
  547. package/src/schemas/provider-subsets.ts +0 -538
  548. package/src/schemas/registry.ts +0 -355
  549. package/src/schemas/tool-defs.ts +0 -793
  550. package/src/solid.ts +0 -173
  551. package/src/state/index.ts +0 -44
  552. package/src/state/messages.ts +0 -53
  553. package/src/state/mock.ts +0 -297
  554. package/src/state/parts.ts +0 -295
  555. package/src/state/persistence.ts +0 -180
  556. package/src/state/stream.ts +0 -246
  557. package/src/state/suggestions.ts +0 -9
  558. package/src/state/threads.ts +0 -142
  559. package/src/test-utils/fake-clock.ts +0 -88
  560. package/src/types.ts +0 -95
  561. package/src/ui/action-icons.ts +0 -53
  562. package/src/ui/agent-card.tsx +0 -218
  563. package/src/ui/avatar.tsx +0 -23
  564. package/src/ui/badge.tsx +0 -21
  565. package/src/ui/button.tsx +0 -49
  566. package/src/ui/card.tsx +0 -245
  567. package/src/ui/checkbox-group.tsx +0 -153
  568. package/src/ui/checkbox.tsx +0 -63
  569. package/src/ui/collapsible.tsx +0 -163
  570. package/src/ui/command.tsx +0 -103
  571. package/src/ui/dialog.tsx +0 -223
  572. package/src/ui/dock.tsx +0 -630
  573. package/src/ui/dropdown.tsx +0 -636
  574. package/src/ui/editable-label.tsx +0 -112
  575. package/src/ui/hover-card.tsx +0 -345
  576. package/src/ui/icon.tsx +0 -167
  577. package/src/ui/input.tsx +0 -391
  578. package/src/ui/kbd.tsx +0 -118
  579. package/src/ui/nav.tsx +0 -282
  580. package/src/ui/notice.tsx +0 -84
  581. package/src/ui/overlay.tsx +0 -277
  582. package/src/ui/pane-grid.tsx +0 -117
  583. package/src/ui/pane-group.tsx +0 -291
  584. package/src/ui/pane.tsx +0 -193
  585. package/src/ui/popover.tsx +0 -106
  586. package/src/ui/progress-bar.tsx +0 -83
  587. package/src/ui/prompt-dock.tsx +0 -145
  588. package/src/ui/radio.tsx +0 -150
  589. package/src/ui/resizable.tsx +0 -693
  590. package/src/ui/scroll-area.tsx +0 -26
  591. package/src/ui/segmented.tsx +0 -109
  592. package/src/ui/select.tsx +0 -168
  593. package/src/ui/separator.tsx +0 -10
  594. package/src/ui/settings-group.tsx +0 -67
  595. package/src/ui/skeleton.tsx +0 -73
  596. package/src/ui/slider.tsx +0 -178
  597. package/src/ui/status.tsx +0 -48
  598. package/src/ui/switch.tsx +0 -119
  599. package/src/ui/tabs.tsx +0 -168
  600. package/src/ui/textarea.tsx +0 -21
  601. package/src/ui/tooltip.tsx +0 -118
  602. package/src/utils/cn.ts +0 -30
  603. package/src/wire/chunk.ts +0 -248
  604. package/src/wire/consume.ts +0 -599
  605. package/src/wire/diagnostics.ts +0 -727
  606. package/src/wire/encode-probe.ts +0 -214
  607. package/src/wire/encode.ts +0 -947
  608. package/src/wire/files.ts +0 -342
  609. package/src/wire/formats/anthropic.ts +0 -274
  610. package/src/wire/formats/openai.ts +0 -228
  611. package/src/wire/index.ts +0 -95
  612. package/src/wire/media-types.ts +0 -344
  613. package/src/wire/read.ts +0 -396
  614. package/src/wire/sink-helpers.ts +0 -50
  615. package/src/wire/sse.ts +0 -153
@@ -1,765 +0,0 @@
1
- import { type JSX, For, Index, Switch, Match, createMemo, createSignal, splitProps, Show } from "solid-js";
2
- import { Tooltip } from "../ui/tooltip";
3
- import { Copy, Check } from "lucide-solid";
4
- import { cn } from "../utils/cn";
5
- import { Markdown } from "./markdown";
6
- import { Button } from "../ui/button";
7
- import { actionIcon, BUILTIN_ACTION_LABEL } from "../ui/action-icons";
8
- import type { ChatMessageAction, CustomAction, FeedbackVote, MessagePart, MessageSource } from "../elements/chat-types";
9
- import { useChatConfig, textClass } from "../primitives/chat-config";
10
- import { Reasoning, ReasoningTrigger, ReasoningContent } from "./reasoning";
11
- import { Loader } from "./loader";
12
- import { Tool } from "./tool";
13
- import {
14
- Attachments,
15
- Attachment,
16
- AttachmentPreview,
17
- AttachmentInfo,
18
- AttachmentHoverCard,
19
- AttachmentHoverCardTrigger,
20
- AttachmentHoverCardContent,
21
- getAttachmentLabel,
22
- getMediaCategory,
23
- } from "./attachments";
24
- import { Source, SourceTrigger, SourceContent, SourceList } from "./source";
25
- import { CardRenderer, type CardSchemaMap } from "./card-renderer";
26
- import type { CardComponentMap } from "../primitives/card-registry";
27
-
28
- // --- Message ---
29
-
30
- /** Who is speaking in a message row. This is the SEMANTIC role of the message,
31
- * not an ARIA role — see `MessageProps['role']`. */
32
- export type MessageRole = 'user' | 'assistant' | 'system';
33
-
34
- /** The accessible name given to a row that declares a speaker. `role="article"`
35
- * supports naming; the bare `<div>` a role-less `<Message>` renders does not,
36
- * so the label is only attached alongside that role. */
37
- const MESSAGE_ROLE_LABEL: Record<MessageRole, string> = {
38
- user: 'User message',
39
- assistant: 'Assistant message',
40
- system: 'System message',
41
- };
42
-
43
- export interface MessageProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, 'role'> {
44
- children: JSX.Element;
45
- /** Who is speaking: `'user'`, `'assistant'` or `'system'`.
46
- *
47
- * This SHADOWS the inherited ARIA `role` attribute on purpose, and is the
48
- * reason `JSX.HTMLAttributes` is `Omit`ted above. Before this existed, `role`
49
- * resolved to ARIA and was spread straight onto the row, so `<Message
50
- * role="user">` shipped `role="user"` on a div — not a valid ARIA role, and a
51
- * critical axe `aria-roles` violation ("Role must be one of the valid ARIA
52
- * roles: user") on every message that used the prop. Chromium discards the
53
- * unknown token and computes `generic`, so the damage was a failed a11y audit
54
- * and a row with no accessible role or name at all, not a mis-announced one.
55
- *
56
- * It is now consumed here and never reaches the DOM. What the row gets
57
- * instead is a VALID ARIA role that can carry a name — `role="article"` plus
58
- * an `aria-label` naming the speaker — and `data-role` for styling and
59
- * querying. Omit the prop and the row stays an unlabelled `<div>`, exactly as
60
- * before, so the many role-less call sites are untouched.
61
- *
62
- * The trade-off: the row's ARIA role can no longer be set through this prop.
63
- * Pass `aria-label` (or any other ARIA attribute) to override the default
64
- * naming — the spread below still wins over what this computes. */
65
- role?: MessageRole;
66
- }
67
-
68
- function Message(props: MessageProps) {
69
- const [local, rest] = splitProps(props, ["children", "class", "role"]);
70
- return (
71
- <div
72
- part="row"
73
- class={cn("flex items-start gap-3", local.class)}
74
- data-role={local.role}
75
- role={local.role ? 'article' : undefined}
76
- aria-label={local.role ? MESSAGE_ROLE_LABEL[local.role] : undefined}
77
- {...rest}
78
- >
79
- {local.children}
80
- </div>
81
- );
82
- }
83
-
84
- // --- MessageAvatar ---
85
-
86
- export interface MessageAvatarProps {
87
- /** Avatar image URL. Optional: with no `src` the component renders `fallback`
88
- * (initials), which is the whole point of having a fallback — requiring `src`
89
- * forced `<MessageAvatar src="" …/>` at every initials-only call site. */
90
- src?: string;
91
- /** Alt text for the image. Only meaningful alongside `src`; defaults to `''`
92
- * so an avatar stays decorative rather than announcing a filename. */
93
- alt?: string;
94
- fallback?: string;
95
- class?: string;
96
- }
97
-
98
- function MessageAvatar(props: MessageAvatarProps) {
99
- return (
100
- <div
101
- part="avatar"
102
- class={cn("h-8 w-8 shrink-0 overflow-hidden rounded-full", props.class)}
103
- >
104
- <Show
105
- when={props.src}
106
- fallback={
107
- <Show when={props.fallback}>
108
- <div class="flex h-full w-full items-center justify-center bg-muted text-xs font-medium text-muted-foreground">
109
- {props.fallback}
110
- </div>
111
- </Show>
112
- }
113
- >
114
- <img
115
- src={props.src}
116
- alt={props.alt ?? ''}
117
- class="h-full w-full object-cover"
118
- />
119
- </Show>
120
- </div>
121
- );
122
- }
123
-
124
- // --- MessageContent ---
125
-
126
- export interface MessageContentProps extends JSX.HTMLAttributes<HTMLDivElement> {
127
- children: JSX.Element | string;
128
- markdown?: boolean;
129
- /** `::part` name(s) exposed on the content node. The body passes
130
- * `"bubble content"` so consumers can target either the rounded bubble or the
131
- * text region from outside the shadow boundary. */
132
- part?: string;
133
- }
134
-
135
- function MessageContent(props: MessageContentProps) {
136
- const [local, rest] = splitProps(props, ["children", "markdown", "class", "part"]);
137
- const config = useChatConfig();
138
- const classNames = () =>
139
- cn(
140
- "min-w-0 rounded-lg p-2 text-foreground bg-secondary max-w-none break-words whitespace-normal",
141
- textClass(config.proseSize()),
142
- local.class,
143
- );
144
-
145
- return (
146
- <Show
147
- when={local.markdown}
148
- fallback={
149
- <div part={local.part} class={classNames()} {...rest}>
150
- {local.children}
151
- </div>
152
- }
153
- >
154
- <Markdown part={local.part} content={local.children as string} class={classNames()} />
155
- </Show>
156
- );
157
- }
158
-
159
- // --- MessageActions ---
160
-
161
- export interface MessageActionsProps extends JSX.HTMLAttributes<HTMLDivElement> {
162
- children: JSX.Element;
163
- }
164
-
165
- function MessageActions(props: MessageActionsProps) {
166
- const [local, rest] = splitProps(props, ["children", "class"]);
167
- return (
168
- <div
169
- class={cn(
170
- "flex items-center gap-0.5 mt-0.5",
171
- local.class,
172
- )}
173
- {...rest}
174
- >
175
- {local.children}
176
- </div>
177
- );
178
- }
179
-
180
- // --- MessageActionBar ---
181
-
182
- export interface MessageActionBarProps {
183
- /** Built-in action names and/or custom action descriptors, in order. */
184
- actions: (ChatMessageAction | CustomAction)[];
185
- /** `'always'` (default) keeps the bar visible; `'hover'` reveals it on
186
- * parent `.group` hover. */
187
- reveal?: 'always' | 'hover';
188
- /** Fired with the built-in name or the custom action id when a button is clicked. */
189
- onAction: (id: string) => void;
190
- /** The active feedback vote. When `'like'`/`'dislike'` is set, that button is
191
- * marked pressed (filled) and the OTHER vote button animates out. `undefined`
192
- * shows both. Pure/prop-driven so the bar survives re-renders. */
193
- activeFeedback?: FeedbackVote;
194
- /** When true, the `copy` button shows its emerald check icon instead of the
195
- * copy glyph (cleared by the owner after ~2s). */
196
- copied?: boolean;
197
- class?: string;
198
- }
199
-
200
- /** Normalize a bar entry (string built-in or custom object) to a uniform shape. */
201
- function normalizeAction(a: ChatMessageAction | CustomAction) {
202
- if (typeof a === 'string') {
203
- return { id: a, label: BUILTIN_ACTION_LABEL[a], Icon: actionIcon(a) };
204
- }
205
- return { id: a.id, label: a.label, Icon: actionIcon(a.icon) };
206
- }
207
-
208
- /** Is this entry one of the two feedback votes? */
209
- function feedbackVoteOf(a: ChatMessageAction | CustomAction): FeedbackVote | undefined {
210
- return a === 'like' || a === 'dislike' ? a : undefined;
211
- }
212
-
213
- /**
214
- * The shared message action toolbar. Renders one ghost icon button per entry —
215
- * built-in names pull their label+icon from the curated registry; custom
216
- * descriptors use their `label` plus `actionIcon(icon)` (label-only when the
217
- * icon is unknown or absent). `reveal="hover"` makes the bar fade in on the
218
- * parent `.group`'s hover.
219
- *
220
- * Pure/prop-driven: feedback (`activeFeedback`) and copy (`copied`) state are
221
- * owned by the parent facade and passed in — the bar holds no internal signals,
222
- * so it survives the new-array-per-chunk re-renders of a streaming thread. With
223
- * a vote active, the chosen `like`/`dislike` button is marked `aria-pressed` +
224
- * filled and the other vote button collapses its width (sliding the active thumb
225
- * into its place) via a 0fr↔1fr grid transition. The
226
- * `copy` button swaps to an emerald check while `copied`.
227
- */
228
- function MessageActionBar(props: MessageActionBarProps) {
229
- return (
230
- <MessageActions
231
- part="actions"
232
- class={cn(
233
- 'mt-1 flex gap-0',
234
- props.reveal === 'hover' && 'opacity-0 transition-opacity group-hover:opacity-100',
235
- props.class,
236
- )}
237
- >
238
- <For each={props.actions}>
239
- {(a) => {
240
- const item = normalizeAction(a);
241
- const tooltipText = () => (typeof a !== 'string' && a.tooltip) ? a.tooltip : item.label;
242
- const vote = feedbackVoteOf(a);
243
- // A vote button is the active one when it matches the resolved vote.
244
- const isActiveVote = () => vote !== undefined && props.activeFeedback === vote;
245
- // The COPY button reflects the copied check.
246
- const isCopy = item.id === 'copy';
247
- const showCheck = () => isCopy && props.copied === true;
248
-
249
- // Factory (not a shared node): each Show branch gets its own Button so
250
- // the eager DOM node is never referenced from two places.
251
- const button = () => (
252
- <Button
253
- variant="ghost"
254
- size="icon-sm"
255
- class={cn('rounded-full', isActiveVote() && 'text-primary')}
256
- data-action={item.id}
257
- aria-label={showCheck() ? 'Copied' : item.label}
258
- aria-pressed={vote !== undefined ? isActiveVote() : undefined}
259
- onClick={() => props.onAction(item.id)}
260
- >
261
- <Show
262
- when={showCheck()}
263
- fallback={
264
- <Show when={item.Icon} fallback={<span class="px-1 text-xs">{item.label}</span>}>
265
- {(Icon) => {
266
- const I = Icon();
267
- return <I class={cn('size-3.5', isActiveVote() && 'fill-current')} />;
268
- }}
269
- </Show>
270
- }
271
- >
272
- <Check class="size-3.5 text-emerald-400" />
273
- </Show>
274
- </Button>
275
- );
276
- // Icon-only buttons get a tooltip; label-only buttons (text already
277
- // visible) don't.
278
- const rendered = () => (
279
- <Show when={item.Icon} fallback={button()}>
280
- <Tooltip content={tooltipText()}>{button()}</Tooltip>
281
- </Show>
282
- );
283
-
284
- // When the OTHER vote is active, this vote button collapses — its WIDTH
285
- // animates to zero via a 0fr↔1fr grid so the remaining thumb slides into
286
- // its place, while it fades out; it slides + fades back on un-vote. (Kept
287
- // mounted-but-collapsed, not unmounted, so the sibling can slide.) No
288
- // vote active → both shown; non-vote entries always render.
289
- return (
290
- <Show when={vote !== undefined} fallback={rendered()}>
291
- {(() => {
292
- const show = () => props.activeFeedback === undefined || props.activeFeedback === vote;
293
- return (
294
- <span
295
- data-feedback-collapsed={show() ? undefined : ''}
296
- class={cn(
297
- 'grid transition-[grid-template-columns,opacity] duration-300 ease-out',
298
- show() ? 'grid-cols-[1fr] opacity-100' : 'grid-cols-[0fr] opacity-0',
299
- )}
300
- >
301
- <span class="min-w-0 overflow-hidden">{rendered()}</span>
302
- </span>
303
- );
304
- })()}
305
- </Show>
306
- );
307
- }}
308
- </For>
309
- </MessageActions>
310
- );
311
- }
312
-
313
- // --- MessageBody ---
314
-
315
- export interface MessageBodyProps {
316
- /** The message's ordered parts (text, reasoning, tool, card, source, file),
317
- * rendered in a single pass in the order they appear. A run of consecutive
318
- * `source` parts renders as ONE citation row (`part="citations"`), placed
319
- * OUTSIDE the message bubble so a citation is never confused with a link the
320
- * model typed into its prose. */
321
- parts: MessagePart[];
322
- /** Add/override card type -> component entries, forwarded to `CardRenderer`
323
- * for `card` parts. */
324
- cardTypes?: CardComponentMap;
325
- /** JSON Schemas for the card types this app renders, keyed by envelope type,
326
- * forwarded to `CardRenderer` for `card` parts. The companion of `cardTypes`:
327
- * that says what DRAWS a card, this says what a VALID one looks like.
328
- * `createCardRegistry(...).validationSchemas` is exactly this shape. Without it
329
- * the kit checks its own seven built-ins and leaves your own card type
330
- * unvalidated. A schema here WINS over a built-in of the same name. */
331
- cardSchemas?: CardSchemaMap;
332
- /** The custom-element host node to emit card events off when no `CardProvider`
333
- * is above this body, forwarded to `CardRenderer` as `hostElement`. The
334
- * `<kai-chat>`/`<kai-message>`/`<kai-thread>` facades pass their own element,
335
- * so a `card` part's events leave as the bubbling `kai-card` CustomEvent
336
- * instead of being silently discarded. */
337
- cardHostElement?: HTMLElement;
338
- /** Whether this is a user message (right-aligned bubble) vs an assistant
339
- * message (full-width transparent). */
340
- isUser: boolean;
341
- /** Whether text parts render as markdown. */
342
- markdown: boolean;
343
- /** Action-bar entries — built-in names and/or custom descriptors. When empty
344
- * the bar is not rendered. */
345
- actions?: (ChatMessageAction | CustomAction)[];
346
- /** `'always'` (default) keeps the bar visible; `'hover'` reveals it on parent
347
- * `.group` hover. */
348
- actionsReveal?: 'always' | 'hover';
349
- /** Fired with the built-in name or custom id when an action is clicked. */
350
- onAction?: (id: string) => void;
351
- /** The currently-active feedback vote, so the bar can mark like/dislike and
352
- * hide the other. */
353
- activeFeedback?: FeedbackVote;
354
- /** When true, the copy button shows its "copied" check icon. */
355
- copied?: boolean;
356
- /** Whether this message is the one currently streaming. Forwarded to each
357
- * reasoning part's `<Reasoning>` so the disclosure auto-opens while the
358
- * model is thinking and settles back once the stream ends. Without it the
359
- * user watches a static collapsed "Reasoning" label for the whole thinking
360
- * window. The caller owns the definition of "streaming" — for
361
- * `ChatThread` that is `loading` + being the last assistant message. */
362
- isStreaming?: boolean;
363
- /** How a `reasoning` part renders. `'full'` (default) is the current
364
- * behavior: the collapsible `<Reasoning>` disclosure, with the "Thinking…"
365
- * shimmer on its trigger while `isStreaming`. `'compact'` drops the
366
- * disclosure entirely and shows only a shimmer loader while the part is
367
- * streaming — nothing once it settles, so there is no expandable detail to
368
- * open. `'off'` renders the part not at all, in either state. Kit-decides-
369
- * HOW: this is a display-mode fact about the medium, not a per-message
370
- * toggle, so it applies uniformly to every reasoning part in the body. */
371
- reasoningMode?: 'full' | 'compact' | 'off';
372
- /** Seeds the reasoning disclosure open AND keeps it tracking the stream
373
- * (open while streaming, closes when it settles): the pre-Task-19f `full`
374
- * behavior. Default false/absent: the panel starts closed (just the
375
- * "Thinking" shimmer chip) and only opens on click, the current default
376
- * (owner ruling, 2026-08-26). Meaningless when `reasoningMode` is
377
- * `'compact'`/`'off'` (no disclosure exists to open). */
378
- reasoningDefaultOpen?: boolean;
379
- /** INJECT slot projected at the TOP of the body — above the reasoning / tools /
380
- * content. A per-message header: a model-name label, a role + timestamp line.
381
- * In the `<kai-message>` shadow this is `<slot name="before-body" />`. */
382
- beforeBody?: JSX.Element;
383
- /** INJECT slot projected at the BOTTOM of the body — below the action bar. A
384
- * citation / sources row, a token-cost / latency line. In the `<kai-message>`
385
- * shadow this is `<slot name="after-body" />`. */
386
- afterBody?: JSX.Element;
387
- }
388
-
389
- /** One render group over an ordered `parts` array. Two part types collapse runs:
390
- * consecutive `file` parts become a single `'files'` group so they share one
391
- * `<Attachments>` row (matching the pre-parts layout) instead of each opening
392
- * its own, and consecutive `source` parts become a single `'sources'` group so
393
- * the N citations one search produced are ONE wrapped row rather than N stacked
394
- * rows. Every other part is its own `'single'` group. Pure and order-preserving:
395
- * it only decides where the wrapper boundaries fall, never reorders or drops
396
- * anything, so a group sits exactly where its parts sat in `parts`. */
397
- export type MessagePartGroup =
398
- | { kind: 'single'; part: Exclude<MessagePart, { type: 'file' } | { type: 'source' }> }
399
- | { kind: 'files'; parts: Extract<MessagePart, { type: 'file' }>[] }
400
- | { kind: 'sources'; parts: Extract<MessagePart, { type: 'source' }>[] };
401
-
402
- export function groupMessageParts(parts: MessagePart[]): MessagePartGroup[] {
403
- const groups: MessagePartGroup[] = [];
404
- for (const part of parts) {
405
- if (part.type === 'file') {
406
- const last = groups[groups.length - 1];
407
- if (last?.kind === 'files') {
408
- groups[groups.length - 1] = { kind: 'files', parts: [...last.parts, part] };
409
- continue;
410
- }
411
- groups.push({ kind: 'files', parts: [part] });
412
- continue;
413
- }
414
- if (part.type === 'source') {
415
- const last = groups[groups.length - 1];
416
- if (last?.kind === 'sources') {
417
- groups[groups.length - 1] = { kind: 'sources', parts: [...last.parts, part] };
418
- continue;
419
- }
420
- groups.push({ kind: 'sources', parts: [part] });
421
- continue;
422
- }
423
- groups.push({ kind: 'single', part });
424
- }
425
- return groups;
426
- }
427
-
428
- /** The citation chip's label. `index` when the model numbered its citations;
429
- * otherwise `undefined` so `SourceTrigger` falls back to the domain. A source
430
- * with NO url has no domain to fall back to, so its title (then a generic word)
431
- * stands in rather than rendering an empty chip. */
432
- function citationLabel(s: MessageSource): string | number | undefined {
433
- if (s.index !== undefined) return s.index;
434
- if (s.url) return undefined;
435
- return s.title || 'Source';
436
- }
437
-
438
- /** The hover card's headline. Every field is optional, so fall back through
439
- * title -> url -> a generic word. */
440
- function citationTitle(s: MessageSource): string {
441
- return s.title || s.url || 'Source';
442
- }
443
-
444
- /** Narrow a group to one variant IN A SINGLE READ.
445
- *
446
- * The render body below reads its group/part through accessors (see the
447
- * `<Index>` note in `MessageBody`), and TypeScript cannot narrow a
448
- * discriminated union across two separate accessor CALLS —
449
- * `g().kind === 'files' && g()` leaves the second call widened, because as far
450
- * as the compiler knows the two calls could return different values. So the
451
- * test and the cast happen together, on one already-read value. Returns
452
- * `false` rather than `undefined` so it reads as a plain falsy `<Match when>`. */
453
- function groupAs<T extends MessagePartGroup['kind']>(
454
- group: MessagePartGroup,
455
- kind: T,
456
- ): Extract<MessagePartGroup, { kind: T }> | false {
457
- return group.kind === kind ? (group as Extract<MessagePartGroup, { kind: T }>) : false;
458
- }
459
-
460
- /** The same single-read narrowing for `MessagePart`. */
461
- function partAs<T extends MessagePart['type']>(
462
- part: MessagePart,
463
- type: T,
464
- ): Extract<MessagePart, { type: T }> | false {
465
- return part.type === type ? (part as Extract<MessagePart, { type: T }>) : false;
466
- }
467
-
468
- /**
469
- * The shared message body: the message's `parts` rendered in a single ordered
470
- * pass (text, reasoning, tool calls, generative-UI cards, citations and file
471
- * attachments interleaved exactly as they appear), followed by the action bar.
472
- * Runs of `source` and `file` parts each collapse into one row. This is the
473
- * single source of truth for how a message renders, consumed by `ChatThread`
474
- * (the `<For>` over `messages`), the standalone `<kai-message>` facade, and (in
475
- * future) `kai-compare` for each candidate. Pure/prop-driven: all interaction
476
- * state (copied, feedback vote) is owned above and passed in.
477
- */
478
- function MessageBody(props: MessageBodyProps) {
479
- const groups = createMemo(() => groupMessageParts(props.parts));
480
- return (
481
- <>
482
- {/* before-body (inject): a per-message header above everything else. */}
483
- <Show when={props.beforeBody}>{props.beforeBody}</Show>
484
- {/* <Index>, NOT <For>, on purpose — this is load-bearing.
485
- *
486
- * A streaming message re-renders once per delta with a brand-new `parts`
487
- * array (a new reference IS the re-render signal), and
488
- * `groupMessageParts` allocates fresh wrapper objects on top of that. A
489
- * <For> is REFERENCE-keyed, so every chunk looks like an entirely new
490
- * list and every row is torn down and rebuilt. Everything the user has
491
- * done inside a row dies with it: expanding a tool panel or a reasoning
492
- * block mid-stream silently did nothing, because the disclosure opened
493
- * and was discarded microseconds later by the next token (a live probe
494
- * caught the collapsibles' `createUniqueId()` walking cl-9 -> cl-11 ->
495
- * cl-15 across three deltas).
496
- *
497
- * <Index> keys by POSITION and hands each row its value as a SIGNAL, so
498
- * a row stays mounted while its content keeps updating. That is exactly
499
- * the shape of a stream: the folds behind `parts`
500
- * (appendTextPart/appendReasoningPart/upsertToolPart) only ever append
501
- * to the end or replace one part IN PLACE with the same variant — never
502
- * reorder, never change a part's type — so a part's position is a stable
503
- * identity, and a growing text/reasoning block or a tool patched from
504
- * `input-streaming` to `output-available` reaches the DOM through the
505
- * accessor instead of through a remount.
506
- *
507
- * The trade-off of position-keying: splicing a part out of the MIDDLE of
508
- * a message shifts the rows after it, so their local state (an open
509
- * disclosure) stays with the position rather than following the part.
510
- * <For> got that right for a STATIC array and got streaming wrong every
511
- * single time — no consumer splices mid-message, every consumer streams.
512
- *
513
- * This only works while the children read through the accessors below:
514
- * capturing `g().part` once re-freezes the row at its first delta. */}
515
- <Index each={groups()}>
516
- {(group) => (
517
- <Switch fallback={null}>
518
- <Match when={groupAs(group(), 'files')}>
519
- {(g) => (
520
- /* `grid`, NOT `inline`. The inline chip gives an image a 20x20
521
- preview — a thumbnail nobody can read — while the 96px tile
522
- and the hover-card full preview both already existed here and
523
- the thread used neither.
524
-
525
- WHY GRID AND NOT LIST, since `list` shows the filename
526
- outright: `list` stacks (`flex-col`), so a message carrying
527
- four attachments becomes four full-width rows and pushes the
528
- conversation off screen. `grid` is `flex-wrap w-fit`, so the
529
- same four are one 96px-tall row of tiles. Density is what
530
- keeps a thread readable, and it is the whole reason the
531
- thread is not the composer's chip strip.
532
-
533
- A grid tile draws no filename of its own, and hiding one
534
- behind the hover card is not good enough: that serves a
535
- pointer and nothing else. So `<AttachmentInfo>` renders a
536
- VISIBLE truncated caption on every non-image tile — no hover,
537
- no focus, no tap required — and the hover card is an upgrade
538
- to the full name and media type rather than the only way to
539
- get either. */
540
- <Attachments variant="grid" class={props.isUser ? 'mb-2 ml-auto' : 'mb-2'}>
541
- {/* Reference-keyed <For> is right HERE: the run's part objects
542
- are carried over untouched by the folds, and an attachment
543
- holds no state worth preserving. */}
544
- <For each={g().parts}>
545
- {(fp) => (
546
- <Attachment data={fp.attachment}>
547
- <AttachmentHoverCard>
548
- <AttachmentHoverCardTrigger class="block size-full">
549
- <AttachmentPreview />
550
- <AttachmentInfo />
551
- </AttachmentHoverCardTrigger>
552
- <AttachmentHoverCardContent>
553
- {/* An image gets the full preview; everything else
554
- gets the name and type the tile could not fit. */}
555
- <Show
556
- when={
557
- getMediaCategory(fp.attachment) === 'image' &&
558
- fp.attachment.type === 'file' &&
559
- fp.attachment.url
560
- }
561
- fallback={
562
- <>
563
- <div class="text-body font-medium">
564
- {getAttachmentLabel(fp.attachment)}
565
- </div>
566
- <Show when={fp.attachment.mediaType}>
567
- <div class="text-muted-foreground text-caption">
568
- {fp.attachment.mediaType}
569
- </div>
570
- </Show>
571
- </>
572
- }
573
- >
574
- <img
575
- alt={getAttachmentLabel(fp.attachment)}
576
- class="block max-h-64 max-w-xs rounded object-contain"
577
- src={fp.attachment.url}
578
- />
579
- </Show>
580
- </AttachmentHoverCardContent>
581
- </AttachmentHoverCard>
582
- </Attachment>
583
- )}
584
- </For>
585
- </Attachments>
586
- )}
587
- </Match>
588
- <Match when={groupAs(group(), 'sources')}>
589
- {(g) => (
590
- // OUTSIDE the bubble, deliberately. A citation nested inside
591
- // `MessageContent` is indistinguishable from a link the MODEL
592
- // typed into its prose — which is exactly how the first version
593
- // of the S12 conformance check passed while proving nothing.
594
- // `SourceList` is its own container, so the row is a sibling of
595
- // the content part, and `part="citations"` lets a consumer target
596
- // it through the shadow boundary.
597
- <SourceList part="citations" class={props.isUser ? 'justify-end' : undefined}>
598
- {/* Reference-keyed <For> is right HERE, as with files: the
599
- run's part objects are carried over untouched by the folds. */}
600
- <For each={g().parts}>
601
- {(sp) => (
602
- <Source href={sp.source.url}>
603
- <SourceTrigger label={citationLabel(sp.source)} />
604
- <SourceContent
605
- title={citationTitle(sp.source)}
606
- description={sp.source.snippet ?? ''}
607
- />
608
- </Source>
609
- )}
610
- </For>
611
- </SourceList>
612
- )}
613
- </Match>
614
- <Match when={groupAs(group(), 'single')}>
615
- {(g) => {
616
- // An ACCESSOR, never a captured value: the row outlives the
617
- // delta that rebuilt this part, so every read below has to go
618
- // through here for the new content to land. `partAs` does the
619
- // type test and the narrowing cast in one read (see its note).
620
- const part = () => g().part;
621
- const reasoning = () => partAs(part(), 'reasoning');
622
- // A reasoning part with NO text is a round-trip carrier, not
623
- // something to show. Anthropic's redacted_thinking blocks carry
624
- // an opaque blob with no readable text, and the block assembled
625
- // at content_block_stop carries the verbatim payload the encoder
626
- // must echo back. Both are empty-text parts that MUST stay in
627
- // `parts` (the encoder needs them, in order) and must not render
628
- // a blank disclosure.
629
- const carrierOnly = () => { const r = reasoning(); return r !== false && r.text === ''; };
630
- const shownReasoning = () => { const r = reasoning(); return r !== false && r.text !== '' && r; };
631
- return (
632
- <Switch fallback={null}>
633
- <Match when={partAs(part(), 'text')}>
634
- {(p) => (
635
- <MessageContent
636
- part="bubble content"
637
- markdown={props.markdown}
638
- class={props.isUser
639
- // Content token, not the brand token: `--color-primary`
640
- // is the documented consumer brand override
641
- // (theme.css `--kai-color-primary`), so toking message
642
- // TEXT to it means every consumer that brands primary
643
- // gets brand-colored message text. `text-foreground` is
644
- // already `MessageContent`'s base color (matches the
645
- // assistant path's `bg-transparent p-0`, which carries
646
- // no color override and falls through to the same
647
- // base) — dropping `text-primary` here just lets that
648
- // base apply on the user bubble too.
649
- ? 'bg-muted max-w-[85%] rounded-2xl px-4 py-2'
650
- : 'bg-transparent p-0'}
651
- >
652
- {p().text}
653
- </MessageContent>
654
- )}
655
- </Match>
656
- <Match when={carrierOnly()}>{null}</Match>
657
- <Match when={shownReasoning()}>
658
- {(p) => {
659
- // Default 'full' is the pre-existing DISPLAY MODE byte
660
- // for byte; the OPEN behavior changed under Task 19f —
661
- // it no longer auto-opens while streaming by default
662
- // (owner ruling 2026-08-26). `reasoningDefaultOpen`
663
- // reproduces the old always-auto-opens behavior when set.
664
- const mode = () => props.reasoningMode ?? 'full';
665
- return (
666
- <Switch fallback={null}>
667
- <Match when={mode() === 'full'}>
668
- <Reasoning
669
- class="mb-2 w-full"
670
- isStreaming={props.isStreaming}
671
- defaultOpen={props.reasoningDefaultOpen}
672
- openOnStream={props.reasoningDefaultOpen}
673
- >
674
- <ReasoningTrigger>{p().label ?? 'Reasoning'}</ReasoningTrigger>
675
- <ReasoningContent markdown>{p().text}</ReasoningContent>
676
- </Reasoning>
677
- </Match>
678
- {/* 'compact': the same "Thinking…" shimmer the full
679
- disclosure's trigger shows while streaming — no
680
- <Reasoning>/<ReasoningContent>, so there is no
681
- expandable detail and nothing left once the part
682
- settles (isStreaming false → this Match doesn't
683
- fire, matching 'off'). 'off' never reaches here:
684
- its Match doesn't fire either. */}
685
- <Match when={mode() === 'compact' && props.isStreaming}>
686
- <Loader variant="text-shimmer" text={p().label ?? 'Reasoning'} class="mb-2" />
687
- </Match>
688
- </Switch>
689
- );
690
- }}
691
- </Match>
692
- <Match when={partAs(part(), 'tool')}>
693
- {(p) => <Tool toolPart={p().tool} class="mb-2 w-full" />}
694
- </Match>
695
- <Match when={partAs(part(), 'card')}>
696
- {(p) => <CardRenderer envelope={p().envelope} types={props.cardTypes} schemas={props.cardSchemas} hostElement={props.cardHostElement} />}
697
- </Match>
698
- {/* No `source` match here on purpose: source parts never
699
- reach a 'single' group — they are collapsed into a
700
- 'sources' run above and rendered as one citation row. */}
701
- </Switch>
702
- );
703
- }}
704
- </Match>
705
- </Switch>
706
- )}
707
- </Index>
708
- <Show when={(props.actions?.length ?? 0) > 0}>
709
- <MessageActionBar
710
- actions={props.actions!}
711
- reveal={props.actionsReveal === 'hover' ? 'hover' : 'always'}
712
- activeFeedback={props.activeFeedback}
713
- copied={props.copied}
714
- onAction={(id) => props.onAction?.(id)}
715
- />
716
- </Show>
717
- {/* after-body (inject): a citation row / cost line below the action bar. */}
718
- <Show when={props.afterBody}>{props.afterBody}</Show>
719
- </>
720
- );
721
- }
722
-
723
- // --- MessageAction ---
724
-
725
- export interface MessageActionProps {
726
- tooltip: string;
727
- children: JSX.Element;
728
- side?: "top" | "bottom" | "left" | "right";
729
- class?: string;
730
- }
731
-
732
- function MessageAction(props: MessageActionProps) {
733
- return <>{props.children}</>;
734
- }
735
-
736
- // --- MessageCopyButton ---
737
-
738
- export interface MessageCopyButtonProps {
739
- content: string;
740
- size?: number;
741
- class?: string;
742
- }
743
-
744
- function MessageCopyButton(props: MessageCopyButtonProps) {
745
- const [copied, setCopied] = createSignal(false);
746
- const iconSize = () => props.size ?? 14;
747
-
748
- return (
749
- <button
750
- class={props.class}
751
- aria-label={copied() ? 'Copied' : 'Copy message'}
752
- onClick={() => {
753
- navigator.clipboard.writeText(props.content);
754
- setCopied(true);
755
- setTimeout(() => setCopied(false), 2000);
756
- }}
757
- >
758
- <Show when={copied()} fallback={<Copy size={iconSize()} />}>
759
- <Check size={iconSize()} class="text-emerald-400" />
760
- </Show>
761
- </button>
762
- );
763
- }
764
-
765
- export { Message, MessageAvatar, MessageContent, MessageActions, MessageActionBar, MessageBody, MessageAction, MessageCopyButton };