@kitn.ai/ui 0.16.0 → 0.18.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 (493) hide show
  1. package/README.md +55 -17
  2. package/dist/components/artifact.d.ts +39 -1
  3. package/dist/components/attachment-types.d.ts +12 -0
  4. package/dist/components/attachments.d.ts +2 -10
  5. package/dist/components/card.d.ts +27 -0
  6. package/dist/components/chain-of-thought.d.ts +78 -2
  7. package/dist/components/chat-scope-picker.d.ts +7 -0
  8. package/dist/components/chat-thread.d.ts +39 -16
  9. package/dist/components/choice-card.d.ts +27 -0
  10. package/dist/components/coachmark.d.ts +49 -0
  11. package/dist/components/composer-dom.d.ts +35 -0
  12. package/dist/components/composer-highlight.d.ts +48 -0
  13. package/dist/components/composer-history.d.ts +34 -0
  14. package/dist/components/composer.d.ts +86 -0
  15. package/dist/components/confirm-card.d.ts +17 -0
  16. package/dist/components/conversation-item.d.ts +9 -0
  17. package/dist/components/conversation-list.d.ts +36 -1
  18. package/dist/components/dismissed-stub.d.ts +22 -0
  19. package/dist/components/file-tree.d.ts +15 -0
  20. package/dist/components/form.d.ts +34 -0
  21. package/dist/components/markdown.d.ts +3 -0
  22. package/dist/components/message.d.ts +71 -2
  23. package/dist/components/model-switcher.d.ts +7 -0
  24. package/dist/components/prompt-input.d.ts +13 -4
  25. package/dist/components/prompt-suggestion.d.ts +9 -1
  26. package/dist/components/reasoning.d.ts +14 -1
  27. package/dist/components/response-compare-types.d.ts +66 -0
  28. package/dist/components/response-compare.d.ts +65 -0
  29. package/dist/components/screen.d.ts +46 -0
  30. package/dist/components/tasks-card.d.ts +50 -1
  31. package/dist/components/toast.d.ts +58 -0
  32. package/dist/components/tool-types.d.ts +10 -0
  33. package/dist/components/tool.d.ts +8 -8
  34. package/dist/components/use-card-resolution.d.ts +10 -6
  35. package/dist/components/voice-input.d.ts +27 -0
  36. package/dist/components/voice-output.d.ts +33 -0
  37. package/dist/core-C8fzo39E.js +12 -0
  38. package/dist/custom-elements.json +8472 -1691
  39. package/dist/elements/agent-card.d.ts +1 -0
  40. package/dist/elements/agent-card.js +1 -0
  41. package/dist/elements/artifact.js +1 -0
  42. package/dist/elements/attachments.js +1 -0
  43. package/dist/elements/autoloader.d.ts +2 -0
  44. package/dist/elements/autoloader.js +1 -0
  45. package/dist/elements/avatar.d.ts +1 -0
  46. package/dist/elements/avatar.js +1 -0
  47. package/dist/elements/badge.d.ts +1 -0
  48. package/dist/elements/badge.js +1 -0
  49. package/dist/elements/button.d.ts +1 -0
  50. package/dist/elements/button.js +1 -0
  51. package/dist/elements/card.js +1 -0
  52. package/dist/elements/cards.d.ts +1 -0
  53. package/dist/elements/cards.js +1 -0
  54. package/dist/elements/chain-of-thought.d.ts +0 -12
  55. package/dist/elements/chain-of-thought.js +1 -0
  56. package/dist/elements/chat-scope-picker.js +1 -0
  57. package/dist/elements/chat-types.d.ts +8 -2
  58. package/dist/elements/chat-workspace.js +1 -0
  59. package/dist/elements/chat.js +1 -0
  60. package/dist/elements/checkpoint.js +1 -0
  61. package/dist/elements/choice.js +1 -0
  62. package/dist/elements/chunks/Icon-DLLBeLG5.js +1 -0
  63. package/dist/elements/chunks/action-icons-UB4V5FNq.js +1 -0
  64. package/dist/elements/chunks/arrow-left-C-gwlUmx.js +1 -0
  65. package/dist/elements/chunks/attachments-CgbErf1r.js +1 -0
  66. package/dist/elements/chunks/badge-DTQpgB6N.js +1 -0
  67. package/dist/elements/chunks/bash-InADTalH.js +1 -0
  68. package/dist/elements/chunks/button-XDUM6lXs.js +1 -0
  69. package/dist/elements/chunks/card-CBlFZ-7I.js +1 -0
  70. package/dist/elements/chunks/card-routing-C986KuUA.js +1 -0
  71. package/dist/elements/chunks/chat-thread-BIhmqwNL.js +1 -0
  72. package/dist/elements/chunks/check-hGUoVIKb.js +1 -0
  73. package/dist/elements/chunks/chevron-down-DDoaSUtO.js +1 -0
  74. package/dist/elements/chunks/chevron-right-CdGEUakB.js +1 -0
  75. package/dist/elements/chunks/circle-BKAZdmzb.js +1 -0
  76. package/dist/elements/chunks/circle-check-CmYG-y3I.js +1 -0
  77. package/dist/elements/chunks/circle-x-DewgAEym.js +1 -0
  78. package/dist/elements/chunks/cn-CU7UAWzk.js +1 -0
  79. package/dist/elements/chunks/code-block-DedwxwFI.js +1 -0
  80. package/dist/elements/chunks/collapsible-FfgmTHtM.js +1 -0
  81. package/dist/elements/chunks/composer-Cfbw5HKT.js +65 -0
  82. package/dist/elements/chunks/context-DwJmxlRE.js +1 -0
  83. package/dist/elements/chunks/conversation-list-DsCQMfPq.js +1 -0
  84. package/dist/elements/chunks/core-AYMC6_lb.js +12 -0
  85. package/dist/elements/chunks/css-M7EaDHN_.js +1 -0
  86. package/dist/elements/chunks/default-input-BuqsoENC.js +1 -0
  87. package/dist/elements/chunks/define-rGsaWsLL.js +1 -0
  88. package/dist/elements/chunks/disclosure-CwoAkpMH.js +1 -0
  89. package/dist/elements/chunks/download-DJ06G3Bz.js +1 -0
  90. package/dist/elements/chunks/dropdown-BFg8ri_R.js +1 -0
  91. package/dist/elements/chunks/ellipsis-dlN6YvGw.js +1 -0
  92. package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +141 -0
  93. package/dist/elements/chunks/external-link-DBX2lc_R.js +1 -0
  94. package/dist/elements/chunks/file-text-HfwUx4F9.js +1 -0
  95. package/dist/elements/chunks/file-tree-C6Toj71u.js +1 -0
  96. package/dist/elements/chunks/folder-MYuqa9Xp.js +1 -0
  97. package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +1 -0
  98. package/dist/elements/chunks/github-light-JYsPkUQd.js +1 -0
  99. package/dist/elements/chunks/hover-card-gE7iyXdW.js +1 -0
  100. package/dist/elements/chunks/html-CPZ3oZQ7.js +1 -0
  101. package/dist/elements/chunks/icon-Vqz4ivrY.js +1 -0
  102. package/dist/elements/chunks/index-BCRhi84a.js +1 -0
  103. package/dist/elements/chunks/info-B_toFS0l.js +1 -0
  104. package/dist/elements/chunks/input-gzbHYZvQ.js +1 -0
  105. package/dist/elements/chunks/javascript-C25yR2R2.js +1 -0
  106. package/dist/elements/chunks/json-DxJze_jm.js +1 -0
  107. package/dist/elements/chunks/kbd-n49c4KZm.js +1 -0
  108. package/dist/elements/chunks/link-CKPs9yM0.js +1 -0
  109. package/dist/elements/chunks/loader-q6MamGus.js +1 -0
  110. package/dist/elements/chunks/markdown-DBrcqq4S.js +64 -0
  111. package/dist/elements/chunks/message-CTqaYI0s.js +1 -0
  112. package/dist/elements/chunks/message-feedback-Cvzm03w0.js +1 -0
  113. package/dist/elements/chunks/message-square-CUg9eRCi.js +1 -0
  114. package/dist/elements/chunks/minimize-2-l2klxP6K.js +1 -0
  115. package/dist/elements/chunks/model-switcher-CmyjiHO1.js +1 -0
  116. package/dist/elements/chunks/overlay-C8sOYqjT.js +1 -0
  117. package/dist/elements/chunks/paperclip-42Ia7xHD.js +1 -0
  118. package/dist/elements/chunks/progress-bar-tzKMWAwO.js +1 -0
  119. package/dist/elements/chunks/prompt-suggestion-D3F6vP_A.js +1 -0
  120. package/dist/elements/chunks/reasoning-BJNmmyov.js +1 -0
  121. package/dist/elements/chunks/resizable-BRsk19qI.js +1 -0
  122. package/dist/elements/chunks/rotate-cw-BgcggLHC.js +1 -0
  123. package/dist/elements/chunks/scroll-area-CgGbFFbT.js +1 -0
  124. package/dist/elements/chunks/separator-8hM4GdHE.js +1 -0
  125. package/dist/elements/chunks/settings-CaUIYOg-.js +1 -0
  126. package/dist/elements/chunks/settings-group-CYjOVIZQ.js +1 -0
  127. package/dist/elements/chunks/share-BTYM3Ddt.js +1 -0
  128. package/dist/elements/chunks/skeleton-DsTYrPUe.js +1 -0
  129. package/dist/elements/chunks/slots-DkZ-Cmha.js +1 -0
  130. package/dist/elements/chunks/star-9R3LBQ9n.js +1 -0
  131. package/dist/elements/chunks/store-CYl5Y0_u.js +1 -0
  132. package/dist/elements/chunks/svelte--5p79yCD.js +1 -0
  133. package/dist/elements/chunks/text-shimmer-CaYGv8Se.js +1 -0
  134. package/dist/elements/chunks/textarea-NEr2SLcD.js +1 -0
  135. package/dist/elements/chunks/thumbs-up-DZYZkFfc.js +1 -0
  136. package/dist/elements/chunks/toast-store-ClxVZRcc.js +1 -0
  137. package/dist/elements/chunks/tool-CHZOmoe9.js +1 -0
  138. package/dist/elements/chunks/tooltip-WpHElELC.js +1 -0
  139. package/dist/elements/chunks/triangle-alert-BlS80PUg.js +1 -0
  140. package/dist/elements/chunks/tsx-B8rCNbgL.js +1 -0
  141. package/dist/elements/chunks/typescript-RycA9KXf.js +1 -0
  142. package/dist/elements/chunks/use-card-resolution-VSVoxDeJ.js +1 -0
  143. package/dist/elements/chunks/video-DxTPZqT8.js +1 -0
  144. package/dist/elements/chunks/vue-BmIZj4XD.js +1 -0
  145. package/dist/elements/chunks/x-C1qtndxn.js +1 -0
  146. package/dist/elements/coachmark.d.ts +1 -0
  147. package/dist/elements/coachmark.js +1 -0
  148. package/dist/elements/code-block.js +1 -0
  149. package/dist/elements/command.d.ts +1 -0
  150. package/dist/elements/command.js +1 -0
  151. package/dist/elements/compare.d.ts +1 -0
  152. package/dist/elements/compare.js +1 -0
  153. package/dist/elements/composer.d.ts +1 -0
  154. package/dist/elements/composer.js +1 -0
  155. package/dist/elements/confirm-card.js +1 -0
  156. package/dist/elements/context-meter.js +1 -0
  157. package/dist/elements/conversation-list.d.ts +1 -11
  158. package/dist/elements/conversation-list.js +1 -0
  159. package/dist/elements/default-input.d.ts +20 -9
  160. package/dist/elements/define.d.ts +11 -0
  161. package/dist/elements/dialog.d.ts +1 -0
  162. package/dist/elements/dialog.js +1 -0
  163. package/dist/elements/disclosure.d.ts +37 -0
  164. package/dist/elements/editable-label.d.ts +1 -0
  165. package/dist/elements/editable-label.js +1 -0
  166. package/dist/elements/embed.js +1 -0
  167. package/dist/elements/empty.js +1 -0
  168. package/dist/elements/feedback-bar.js +1 -0
  169. package/dist/elements/file-tree.js +1 -0
  170. package/dist/elements/file-upload.js +1 -0
  171. package/dist/elements/form.js +1 -0
  172. package/dist/elements/hover-card.d.ts +1 -0
  173. package/dist/elements/hover-card.js +1 -0
  174. package/dist/elements/icon.d.ts +1 -0
  175. package/dist/elements/icon.js +1 -0
  176. package/dist/elements/image.js +1 -0
  177. package/dist/elements/input.d.ts +1 -0
  178. package/dist/elements/input.js +1 -0
  179. package/dist/elements/kbd.d.ts +1 -0
  180. package/dist/elements/kbd.js +1 -0
  181. package/dist/elements/link-preview.js +1 -0
  182. package/dist/elements/loader.js +1 -0
  183. package/dist/elements/markdown.js +1 -0
  184. package/dist/elements/menu.d.ts +1 -0
  185. package/dist/elements/menu.js +1 -0
  186. package/dist/elements/message-skills.d.ts +0 -16
  187. package/dist/elements/message-skills.js +1 -0
  188. package/dist/elements/message.js +1 -0
  189. package/dist/elements/model-switcher.d.ts +1 -11
  190. package/dist/elements/model-switcher.js +1 -0
  191. package/dist/elements/nav.d.ts +1 -0
  192. package/dist/elements/nav.js +1 -0
  193. package/dist/elements/notice.d.ts +1 -0
  194. package/dist/elements/notice.js +1 -0
  195. package/dist/elements/pane-group.d.ts +1 -0
  196. package/dist/elements/pane-group.js +1 -0
  197. package/dist/elements/pane.d.ts +1 -0
  198. package/dist/elements/pane.js +1 -0
  199. package/dist/elements/popover.js +1 -0
  200. package/dist/elements/progress-bar.d.ts +1 -0
  201. package/dist/elements/progress-bar.js +1 -0
  202. package/dist/elements/prompt-dock.d.ts +1 -0
  203. package/dist/elements/prompt-dock.js +1 -0
  204. package/dist/elements/prompt-input.d.ts +1 -9
  205. package/dist/elements/prompt-input.js +1 -0
  206. package/dist/elements/prompt-suggestions.d.ts +0 -6
  207. package/dist/elements/prompt-suggestions.js +1 -0
  208. package/dist/elements/reasoning.js +1 -0
  209. package/dist/elements/register.d.ts +10 -0
  210. package/dist/elements/remote.js +1 -0
  211. package/dist/elements/resizable.d.ts +1 -17
  212. package/dist/elements/resizable.js +1 -0
  213. package/dist/elements/response-stream.js +14 -0
  214. package/dist/elements/screen.d.ts +1 -0
  215. package/dist/elements/screen.js +1 -0
  216. package/dist/elements/scroll-area.d.ts +1 -0
  217. package/dist/elements/scroll-area.js +1 -0
  218. package/dist/elements/scroll-button.js +1 -0
  219. package/dist/elements/search.d.ts +1 -0
  220. package/dist/elements/search.js +1 -0
  221. package/dist/elements/segmented.d.ts +1 -0
  222. package/dist/elements/segmented.js +1 -0
  223. package/dist/elements/separator.d.ts +1 -0
  224. package/dist/elements/separator.js +1 -0
  225. package/dist/elements/setting-item.d.ts +1 -0
  226. package/dist/elements/setting-item.js +1 -0
  227. package/dist/elements/settings-group.d.ts +1 -0
  228. package/dist/elements/settings-group.js +1 -0
  229. package/dist/elements/skeleton.d.ts +1 -0
  230. package/dist/elements/skeleton.js +1 -0
  231. package/dist/elements/slots.d.ts +176 -0
  232. package/dist/elements/source.d.ts +0 -17
  233. package/dist/elements/source.js +1 -0
  234. package/dist/elements/status.d.ts +1 -0
  235. package/dist/elements/status.js +1 -0
  236. package/dist/elements/switch.js +1 -0
  237. package/dist/elements/tabs.d.ts +1 -0
  238. package/dist/elements/tabs.js +1 -0
  239. package/dist/elements/tasks.js +1 -0
  240. package/dist/elements/text-shimmer.js +1 -0
  241. package/dist/elements/thinking-bar.js +1 -0
  242. package/dist/elements/toast.d.ts +1 -0
  243. package/dist/elements/toast.js +1 -0
  244. package/dist/elements/tool.js +1 -0
  245. package/dist/elements/tooltip.d.ts +1 -0
  246. package/dist/elements/tooltip.js +1 -0
  247. package/dist/elements/voice-input.js +1 -0
  248. package/dist/elements/voice-output.d.ts +1 -0
  249. package/dist/elements/voice-output.js +1 -0
  250. package/dist/elements.d.ts +772 -61
  251. package/dist/engine-javascript-C1x7zo1_.js +141 -0
  252. package/dist/index.d.ts +15 -2
  253. package/dist/index.js +14405 -9810
  254. package/dist/kai.es.js +1 -0
  255. package/dist/llms/llms-full.txt +1234 -107
  256. package/dist/llms/llms.txt +4 -4
  257. package/dist/mcp.es.js +217 -6
  258. package/dist/primitives/card-contract.d.ts +20 -4
  259. package/dist/primitives/card-recovery.d.ts +55 -0
  260. package/dist/primitives/composer-model.d.ts +22 -0
  261. package/dist/primitives/composer-triggers.d.ts +19 -0
  262. package/dist/primitives/create-kai-chat.d.ts +38 -0
  263. package/dist/primitives/message-feedback.d.ts +35 -0
  264. package/dist/primitives/toast-store.d.ts +118 -0
  265. package/dist/primitives/use-speech-recognition.d.ts +26 -0
  266. package/dist/react/index.d.ts +1166 -98
  267. package/dist/react/runtime.d.ts +9 -2
  268. package/dist/react/use-kai-chat.d.ts +41 -0
  269. package/dist/react.js +575 -186
  270. package/dist/register-impl-CYWGkgbI.js +141 -0
  271. package/dist/schemas/choice.schema.json +5 -0
  272. package/dist/schemas/tasks.schema.json +7 -2
  273. package/dist/state/index.d.ts +4 -0
  274. package/dist/state/messages.d.ts +11 -0
  275. package/dist/state/stream.d.ts +22 -0
  276. package/dist/state/suggestions.d.ts +4 -0
  277. package/dist/state.js +117 -0
  278. package/dist/theme.tokens.css +87 -0
  279. package/dist/types.d.ts +4 -0
  280. package/dist/ui/agent-card.d.ts +61 -0
  281. package/dist/ui/button.d.ts +5 -2
  282. package/dist/ui/card.d.ts +61 -0
  283. package/dist/ui/collapsible.d.ts +15 -1
  284. package/dist/ui/command.d.ts +33 -0
  285. package/dist/ui/dialog.d.ts +42 -0
  286. package/dist/ui/dropdown.d.ts +95 -1
  287. package/dist/ui/editable-label.d.ts +26 -0
  288. package/dist/ui/hover-card.d.ts +13 -1
  289. package/dist/ui/icon.d.ts +18 -0
  290. package/dist/ui/input.d.ts +33 -0
  291. package/dist/ui/kbd.d.ts +21 -0
  292. package/dist/ui/nav.d.ts +62 -0
  293. package/dist/ui/notice.d.ts +31 -0
  294. package/dist/ui/overlay.d.ts +12 -0
  295. package/dist/ui/pane-grid.d.ts +58 -0
  296. package/dist/ui/pane-group.d.ts +75 -0
  297. package/dist/ui/pane.d.ts +78 -0
  298. package/dist/ui/popover.d.ts +11 -1
  299. package/dist/ui/progress-bar.d.ts +23 -0
  300. package/dist/ui/prompt-dock.d.ts +96 -0
  301. package/dist/ui/resizable.d.ts +12 -0
  302. package/dist/ui/scroll-area.d.ts +4 -0
  303. package/dist/ui/segmented.d.ts +28 -0
  304. package/dist/ui/settings-group.d.ts +32 -0
  305. package/dist/ui/skeleton.d.ts +12 -0
  306. package/dist/ui/stat.d.ts +16 -0
  307. package/dist/ui/status.d.ts +13 -0
  308. package/dist/ui/switch.d.ts +8 -1
  309. package/dist/ui/tabs.d.ts +35 -0
  310. package/dist/ui/tooltip.d.ts +20 -1
  311. package/frameworks/react/index.tsx +1100 -163
  312. package/frameworks/react/runtime.tsx +30 -1
  313. package/frameworks/react/use-kai-chat.tsx +87 -0
  314. package/llms-full.txt +1234 -107
  315. package/llms.txt +4 -4
  316. package/package.json +36 -12
  317. package/src/agent-tooling/mcp/manifest.ts +14 -0
  318. package/src/agent-tooling/mcp/tools/debug.ts +194 -6
  319. package/src/agent-tooling/mcp/tools/reference.ts +32 -0
  320. package/src/agent-tooling/mcp/tools/scaffold.ts +162 -1
  321. package/src/components/artifact.tsx +98 -13
  322. package/src/components/attachment-types.ts +13 -0
  323. package/src/components/attachments.tsx +4 -14
  324. package/src/components/card.tsx +109 -15
  325. package/src/components/chain-of-thought.tsx +210 -1
  326. package/src/components/chat-scope-picker.tsx +13 -3
  327. package/src/components/chat-thread.tsx +238 -137
  328. package/src/components/choice-card.tsx +136 -15
  329. package/src/components/coachmark.tsx +245 -0
  330. package/src/components/component-meta.json +921 -108
  331. package/src/components/composer-dom.ts +159 -0
  332. package/src/components/composer-highlight.ts +242 -0
  333. package/src/components/composer-history.ts +82 -0
  334. package/src/components/composer.tsx +979 -0
  335. package/src/components/confirm-card.tsx +69 -2
  336. package/src/components/conversation-item.tsx +69 -7
  337. package/src/components/conversation-list.tsx +134 -37
  338. package/src/components/dismissed-stub.tsx +80 -0
  339. package/src/components/file-tree.tsx +197 -47
  340. package/src/components/form-widgets.tsx +9 -7
  341. package/src/components/form.tsx +161 -20
  342. package/src/components/image.tsx +3 -5
  343. package/src/components/link-preview.tsx +5 -4
  344. package/src/components/markdown.tsx +5 -2
  345. package/src/components/message.tsx +174 -14
  346. package/src/components/model-switcher.tsx +19 -4
  347. package/src/components/prompt-input.tsx +46 -75
  348. package/src/components/prompt-suggestion.tsx +48 -16
  349. package/src/components/reasoning.tsx +29 -6
  350. package/src/components/response-compare-types.ts +127 -0
  351. package/src/components/response-compare.tsx +460 -0
  352. package/src/components/screen.tsx +176 -0
  353. package/src/components/tasks-card.tsx +374 -23
  354. package/src/components/toast.tsx +486 -0
  355. package/src/components/tool-types.ts +10 -0
  356. package/src/components/tool.tsx +22 -16
  357. package/src/components/use-card-resolution.ts +24 -8
  358. package/src/components/voice-input.tsx +102 -19
  359. package/src/components/voice-output.tsx +202 -0
  360. package/src/elements/agent-card.tsx +67 -0
  361. package/src/elements/artifact.tsx +53 -4
  362. package/src/elements/attachments.tsx +1 -0
  363. package/src/elements/autoloader.ts +89 -0
  364. package/src/elements/avatar.tsx +33 -0
  365. package/src/elements/badge.tsx +32 -0
  366. package/src/elements/button.tsx +126 -0
  367. package/src/elements/card-media.jpg +0 -0
  368. package/src/elements/card.tsx +124 -31
  369. package/src/elements/cards.tsx +81 -7
  370. package/src/elements/chain-of-thought.tsx +77 -32
  371. package/src/elements/chat-scope-picker.tsx +35 -8
  372. package/src/elements/chat-types.ts +9 -2
  373. package/src/elements/chat-workspace.tsx +157 -43
  374. package/src/elements/chat.tsx +49 -25
  375. package/src/elements/choice.tsx +71 -19
  376. package/src/elements/coachmark.tsx +90 -0
  377. package/src/elements/command.tsx +209 -0
  378. package/src/elements/compare.tsx +110 -0
  379. package/src/elements/compiled.css +1 -1
  380. package/src/elements/composer.tsx +151 -0
  381. package/src/elements/confirm-card.tsx +36 -11
  382. package/src/elements/conversation-list.tsx +80 -11
  383. package/src/elements/default-input.tsx +75 -53
  384. package/src/elements/define.tsx +47 -6
  385. package/src/elements/dialog.tsx +98 -0
  386. package/src/elements/disclosure.ts +73 -0
  387. package/src/elements/editable-label.tsx +125 -0
  388. package/src/elements/element-manifest.json +310 -0
  389. package/src/elements/element-meta.json +5954 -1605
  390. package/src/elements/element-types.d.ts +771 -60
  391. package/src/elements/file-tree.tsx +12 -2
  392. package/src/elements/file-upload.tsx +1 -1
  393. package/src/elements/form.tsx +54 -11
  394. package/src/elements/hover-card.tsx +80 -0
  395. package/src/elements/icon-names.json +48 -0
  396. package/src/elements/icon.tsx +41 -0
  397. package/src/elements/input.tsx +203 -0
  398. package/src/elements/kbd.tsx +45 -0
  399. package/src/elements/menu.tsx +217 -0
  400. package/src/elements/message.tsx +84 -55
  401. package/src/elements/model-switcher.tsx +27 -1
  402. package/src/elements/nav.tsx +87 -0
  403. package/src/elements/notice.tsx +53 -0
  404. package/src/elements/pane-group.tsx +119 -0
  405. package/src/elements/pane.tsx +129 -0
  406. package/src/elements/popover.tsx +39 -17
  407. package/src/elements/progress-bar.tsx +39 -0
  408. package/src/elements/prompt-dock.tsx +81 -0
  409. package/src/elements/prompt-input.tsx +112 -63
  410. package/src/elements/prompt-suggestions.tsx +25 -9
  411. package/src/elements/reasoning.tsx +30 -9
  412. package/src/elements/register-impl.ts +41 -3
  413. package/src/elements/register.ts +20 -3
  414. package/src/elements/remote.tsx +4 -0
  415. package/src/elements/resizable.tsx +48 -11
  416. package/src/elements/screen.tsx +90 -0
  417. package/src/elements/scroll-area.tsx +33 -0
  418. package/src/elements/search.tsx +180 -0
  419. package/src/elements/segmented.tsx +135 -0
  420. package/src/elements/separator.tsx +36 -0
  421. package/src/elements/setting-item.tsx +50 -0
  422. package/src/elements/settings-group.tsx +37 -0
  423. package/src/elements/skeleton.tsx +45 -0
  424. package/src/elements/slots.ts +607 -0
  425. package/src/elements/source.tsx +13 -6
  426. package/src/elements/status.tsx +42 -0
  427. package/src/elements/styles.css +19 -0
  428. package/src/elements/switch.tsx +89 -14
  429. package/src/elements/tabs.tsx +95 -0
  430. package/src/elements/tasks.tsx +70 -14
  431. package/src/elements/toast.tsx +89 -0
  432. package/src/elements/tool.tsx +43 -9
  433. package/src/elements/tooltip.tsx +85 -0
  434. package/src/elements/video-poster.jpg +0 -0
  435. package/src/elements/voice-input.tsx +66 -16
  436. package/src/elements/voice-output.tsx +69 -0
  437. package/src/index.ts +35 -2
  438. package/src/primitives/card-contract.ts +14 -5
  439. package/src/primitives/card-recovery.ts +149 -0
  440. package/src/primitives/card-routing.ts +3 -0
  441. package/src/primitives/card-schemas/choice.schema.json +5 -0
  442. package/src/primitives/card-schemas/tasks.schema.json +7 -2
  443. package/src/primitives/composer-model.ts +49 -0
  444. package/src/primitives/composer-triggers.ts +35 -0
  445. package/src/primitives/create-kai-chat.ts +66 -0
  446. package/src/primitives/message-feedback.ts +123 -0
  447. package/src/primitives/toast-store.ts +276 -0
  448. package/src/primitives/use-speech-recognition.ts +135 -0
  449. package/src/state/index.ts +6 -0
  450. package/src/state/messages.ts +36 -0
  451. package/src/state/stream.ts +92 -0
  452. package/src/state/suggestions.ts +9 -0
  453. package/src/types.ts +4 -0
  454. package/src/ui/agent-card.tsx +212 -0
  455. package/src/ui/button.tsx +16 -5
  456. package/src/ui/card.tsx +245 -0
  457. package/src/ui/collapsible.tsx +30 -4
  458. package/src/ui/command.tsx +99 -0
  459. package/src/ui/dialog.tsx +217 -0
  460. package/src/ui/dropdown.tsx +375 -13
  461. package/src/ui/editable-label.tsx +112 -0
  462. package/src/ui/hover-card.tsx +28 -5
  463. package/src/ui/icon.tsx +110 -0
  464. package/src/ui/input.tsx +132 -0
  465. package/src/ui/kbd.tsx +118 -0
  466. package/src/ui/nav.tsx +282 -0
  467. package/src/ui/notice.tsx +84 -0
  468. package/src/ui/overlay.tsx +108 -2
  469. package/src/ui/pane-grid.tsx +116 -0
  470. package/src/ui/pane-group.tsx +280 -0
  471. package/src/ui/pane.tsx +193 -0
  472. package/src/ui/popover.tsx +16 -2
  473. package/src/ui/progress-bar.tsx +83 -0
  474. package/src/ui/prompt-dock.tsx +145 -0
  475. package/src/ui/resizable.tsx +69 -1
  476. package/src/ui/scroll-area.tsx +14 -3
  477. package/src/ui/segmented.tsx +109 -0
  478. package/src/ui/settings-group.tsx +67 -0
  479. package/src/ui/skeleton.tsx +62 -5
  480. package/src/ui/stat.tsx +41 -0
  481. package/src/ui/status.tsx +48 -0
  482. package/src/ui/switch.tsx +49 -23
  483. package/src/ui/tabs.tsx +168 -0
  484. package/src/ui/tooltip.tsx +57 -7
  485. package/theme.css +113 -0
  486. package/dist/components/slash-command.d.ts +0 -15
  487. package/dist/kitn-chat.es.js +0 -1
  488. package/dist/register-impl-wCsFPoh9.js +0 -77
  489. package/dist/register-ujhr1nBS.js +0 -1
  490. package/src/components/slash-command.tsx +0 -232
  491. package/src/elements/framework-usage.json +0 -563
  492. /package/dist/{kitn-chat-provider.d.ts → kai-provider.d.ts} +0 -0
  493. /package/dist/{kitn-chat-provider.es.js → kai-provider.es.js} +0 -0
@@ -0,0 +1,217 @@
1
+ import { For, Show } from 'solid-js';
2
+ import { MoreHorizontal } from 'lucide-solid';
3
+ import {
4
+ Dropdown, DropdownTrigger, DropdownContent, DropdownItem,
5
+ DropdownSeparator, DropdownLabel, DropdownCheckboxItem, DropdownRadioItem,
6
+ DropdownSub, DropdownSubTrigger, DropdownSubContent,
7
+ type DropdownController,
8
+ } from '../ui/dropdown';
9
+ import { renderIcon } from '../ui/icon';
10
+ import { Kbd } from '../ui/kbd';
11
+ import { cn } from '../utils/cn';
12
+ import { defineWebComponent } from './define';
13
+ import { wireDisclosure } from './disclosure';
14
+
15
+ export interface KaiMenuItem {
16
+ /** Emitted in `kai-select` for actionable items. */
17
+ id?: string;
18
+ label?: string;
19
+ /** Named icon (e.g. "paperclip"), image URL / data-URI, or plain text. */
20
+ icon?: string;
21
+ /** e.g. '⌘U' — shown right-aligned, muted. */
22
+ shortcut?: string;
23
+ /** Presence ⇒ a checkbox item (role=menuitemcheckbox). With `radioGroup` set,
24
+ * marks the SELECTED radio item in that group instead. */
25
+ checked?: boolean;
26
+ /** Membership in a single-select group (role=menuitemradio). Items sharing a
27
+ * `radioGroup` are mutually exclusive — the one with `checked: true` shows the
28
+ * checkmark; selecting one emits `{ id, radioGroup }` so the consumer moves
29
+ * the checkmark (the consumer owns state, like checkbox items). */
30
+ radioGroup?: string;
31
+ disabled?: boolean;
32
+ /** A divider (ignores other fields). */
33
+ separator?: boolean;
34
+ /** A non-interactive section label (uses `label`). */
35
+ heading?: boolean;
36
+ /** ⇒ a submenu. */
37
+ items?: KaiMenuItem[];
38
+ }
39
+
40
+ interface Props extends Record<string, unknown> {
41
+ /** Tree of menu items. Set as a JS property — not an HTML attribute. */
42
+ items?: KaiMenuItem[];
43
+ /** Optional placement hint (unused by the underlying Dropdown which always
44
+ * positions bottom-start, kept for future extension). */
45
+ placement?: string;
46
+ /** Built-in trigger: leading icon (a named icon like `"plus"`, an image
47
+ * URL/data-URI, or text). Use this instead of slotting `slot="trigger"` for
48
+ * the common case — a slotted trigger overrides it. */
49
+ triggerIcon?: string;
50
+ /** Built-in trigger: a text label (e.g. `"High"`). */
51
+ triggerLabel?: string;
52
+ /** Built-in trigger: a trailing icon (e.g. `"chevron-down"` for a select look). */
53
+ triggerIconTrailing?: string;
54
+ /** Accessible name for an icon-only trigger (no visible label). */
55
+ label?: string;
56
+ /** Drive/observe open state (Shoelace-style: settable + reflected to the `open`
57
+ * attribute, the menu still self-manages on click/keyboard). Set `el.open = true`,
58
+ * or `<kai-menu open>`; listen for `kai-open-change`. */
59
+ open?: boolean;
60
+ /** Initial open state on mount (uncontrolled seed). */
61
+ defaultOpen?: boolean;
62
+ /** Disable the trigger — click/keyboard and `show()` no longer open the menu. */
63
+ disabled?: boolean;
64
+ }
65
+
66
+ interface Events {
67
+ /**
68
+ * Fired when the user selects a leaf item.
69
+ * - Plain items: `{ id }`.
70
+ * - Checkbox items: `{ id, checked }` where `checked` is the NEW state.
71
+ * - Radio items: `{ id, radioGroup }` — the consumer marks `id` as the selected
72
+ * one in `radioGroup` and clears the others.
73
+ */
74
+ 'kai-select': { id: string; checked?: boolean; radioGroup?: string };
75
+ /** The menu opened or closed (by click, keyboard, Escape, outside-click, or a method). */
76
+ 'kai-open-change': { open: boolean };
77
+ }
78
+
79
+ /**
80
+ * `<kai-menu>` — a cascading action menu driven by a JSON items-tree.
81
+ *
82
+ * Set the `items` property in JavaScript (array, not attribute). The trigger
83
+ * is slotted — put your icon/button content in `slot="trigger"`:
84
+ *
85
+ * ```html
86
+ * <kai-menu>
87
+ * <button slot="trigger" aria-label="Open menu">+</button>
88
+ * </kai-menu>
89
+ * <script type="module">
90
+ * import '@kitn.ai/ui/elements';
91
+ * const menu = document.querySelector('kai-menu');
92
+ * menu.items = [
93
+ * { heading: true, label: 'Actions' },
94
+ * { id: 'attach', label: 'Add files', icon: 'paperclip', shortcut: 'Mod+U' },
95
+ * ];
96
+ * menu.addEventListener('kai-select', (e) => console.log(e.detail));
97
+ * </script>
98
+ * ```
99
+ */
100
+ defineWebComponent<Props, Events>('kai-menu', {
101
+ items: undefined,
102
+ placement: undefined,
103
+ triggerIcon: undefined,
104
+ triggerLabel: undefined,
105
+ triggerIconTrailing: undefined,
106
+ label: undefined,
107
+ open: undefined,
108
+ defaultOpen: undefined,
109
+ disabled: undefined,
110
+ }, (props, ctx) => {
111
+ const { dispatch, flag } = ctx;
112
+ let api: DropdownController | undefined;
113
+
114
+ // The standard overlay surface: settable+reflecting `open`, kai-open-change,
115
+ // show/hide/toggle, disabled-gating. See ./disclosure.
116
+ wireDisclosure(ctx, () => api, () => props.open);
117
+
118
+ function renderItems(items: KaiMenuItem[]) {
119
+ return (
120
+ <For each={items}>
121
+ {(item) => {
122
+ if (item.separator) {
123
+ return <DropdownSeparator />;
124
+ }
125
+ if (item.heading) {
126
+ return <DropdownLabel>{item.label}</DropdownLabel>;
127
+ }
128
+ if (item.items && item.items.length > 0) {
129
+ return (
130
+ <DropdownSub>
131
+ <DropdownSubTrigger>
132
+ <Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
133
+ {item.label}
134
+ </DropdownSubTrigger>
135
+ <DropdownSubContent>
136
+ {renderItems(item.items)}
137
+ </DropdownSubContent>
138
+ </DropdownSub>
139
+ );
140
+ }
141
+ if (item.radioGroup !== undefined) {
142
+ return (
143
+ <DropdownRadioItem
144
+ checked={item.checked}
145
+ disabled={item.disabled}
146
+ onSelect={() => {
147
+ if (item.id) dispatch('kai-select', { id: item.id, radioGroup: item.radioGroup });
148
+ }}
149
+ >
150
+ <Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
151
+ {item.label}
152
+ </DropdownRadioItem>
153
+ );
154
+ }
155
+ if (item.checked !== undefined) {
156
+ return (
157
+ <DropdownCheckboxItem
158
+ checked={item.checked}
159
+ disabled={item.disabled}
160
+ onSelect={() => {
161
+ if (item.id) dispatch('kai-select', { id: item.id, checked: !item.checked });
162
+ }}
163
+ >
164
+ <Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
165
+ {item.label}
166
+ </DropdownCheckboxItem>
167
+ );
168
+ }
169
+ return (
170
+ <DropdownItem
171
+ disabled={item.disabled}
172
+ onSelect={() => { if (item.id) dispatch('kai-select', { id: item.id }); }}
173
+ >
174
+ <Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
175
+ {item.label}
176
+ <Show when={item.shortcut}>
177
+ <span part="shortcut" class="ml-auto pl-4 text-muted-foreground">
178
+ <Kbd keys={item.shortcut!} platform="auto" size="sm" />
179
+ </span>
180
+ </Show>
181
+ </DropdownItem>
182
+ );
183
+ }}
184
+ </For>
185
+ );
186
+ }
187
+
188
+ return (
189
+ <Dropdown
190
+ defaultOpen={flag('defaultOpen')}
191
+ disabled={flag('disabled')}
192
+ controllerRef={(a) => (api = a)}
193
+ >
194
+ <DropdownTrigger
195
+ class={cn(
196
+ 'inline-flex items-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
197
+ props.triggerLabel
198
+ ? 'gap-1.5 px-2 py-1.5 text-sm font-medium text-muted-foreground hover:bg-accent hover:text-foreground'
199
+ : 'justify-center p-1.5 text-foreground hover:bg-muted',
200
+ )}
201
+ aria-label={props.label ?? (props.triggerLabel ? undefined : 'Open menu')}
202
+ >
203
+ {/* Slotted trigger wins; otherwise build one from the trigger* props;
204
+ otherwise fall back to a "more" glyph. */}
205
+ <slot name="trigger">
206
+ <Show when={props.triggerIcon}>{renderIcon(props.triggerIcon, { class: 'size-4 shrink-0' })}</Show>
207
+ <Show when={props.triggerLabel}>{props.triggerLabel}</Show>
208
+ <Show when={props.triggerIconTrailing}>{renderIcon(props.triggerIconTrailing, { class: 'size-3.5 shrink-0 opacity-60' })}</Show>
209
+ <Show when={!props.triggerIcon && !props.triggerLabel}><MoreHorizontal class="size-4" /></Show>
210
+ </slot>
211
+ </DropdownTrigger>
212
+ <DropdownContent class="min-w-[15rem]">
213
+ {renderItems((props.items as KaiMenuItem[] | undefined) ?? [])}
214
+ </DropdownContent>
215
+ </Dropdown>
216
+ );
217
+ });
@@ -1,10 +1,9 @@
1
- import { For, Show, createSignal, onMount, onCleanup } from 'solid-js';
1
+ import { Show, createSignal, onMount, onCleanup } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
+ import { readSlots, MESSAGE_SLOTS } from './slots';
3
4
  import { ChatConfig, useChatConfig, type ProseSize } from '../primitives/chat-config';
4
- import { Message, MessageAvatar, MessageContent, MessageActionBar } from '../components/message';
5
- import { Reasoning, ReasoningTrigger, ReasoningContent } from '../components/reasoning';
6
- import { Tool } from '../components/tool';
7
- import { Attachments, Attachment, AttachmentPreview, AttachmentInfo } from '../components/attachments';
5
+ import { Message, MessageAvatar, MessageBody } from '../components/message';
6
+ import { createMessageFeedback } from '../primitives/message-feedback';
8
7
  import type { ChatMessage } from './chat-types';
9
8
 
10
9
  interface Props extends Record<string, unknown> {
@@ -29,12 +28,19 @@ interface Props extends Record<string, unknown> {
29
28
  avatarSrc?: string;
30
29
  /** Convenience avatar fallback text (used when `message.avatar` is not set). */
31
30
  avatarFallback?: string;
31
+ /** Avatar rail mode. `'none'` omits the avatar rail entirely so the body spans
32
+ * the full row (predictable layout when you never show avatars). Any other
33
+ * value keeps the default behaviour: the built-in avatar when one resolves, or
34
+ * your `slot="avatar"` content when projected (which REPLACES the built-in). */
35
+ avatar?: 'none' | string;
32
36
  }
33
37
 
34
38
  /** Events fired by `<kai-message>`. */
35
39
  interface Events {
36
- /** An action button was clicked. `action` is the built-in name or custom id. */
37
- 'kai-message-action': { messageId: string; action: string };
40
+ /** An action button was clicked. `action` is the built-in name or custom id.
41
+ * `state` is present only for the toggleable feedback votes: `'on'` when a
42
+ * like/dislike is set, `'off'` when re-tapped to clear. */
43
+ 'kai-message-action': { messageId: string; action: string; state?: 'on' | 'off' };
38
44
  }
39
45
 
40
46
  /**
@@ -54,14 +60,36 @@ defineWebComponent<Props, Events>('kai-message', {
54
60
  actionsReveal: 'always',
55
61
  avatarSrc: undefined,
56
62
  avatarFallback: undefined,
57
- }, (props, { dispatch, flag, element }) => {
63
+ avatar: undefined,
64
+ }, (props, { dispatch, flag, element, expose }) => {
58
65
  const outer = useChatConfig();
59
66
  const msg = (): ChatMessage =>
60
67
  props.message ?? { id: 'message', role: props.role ?? 'assistant', content: props.content ?? '' };
68
+ // Copy + vote state lives here (above the rendered body) so it survives a
69
+ // re-render when the host swaps in a fresh `message` object during streaming.
70
+ const feedback = createMessageFeedback({
71
+ emit: (detail) => dispatch('kai-message-action', detail),
72
+ // No `target`: a STANDALONE <kai-message> must not anchor its copy/feedback
73
+ // toast to the individual message (that lands mid-thread in a compose-your-own
74
+ // list). Let them route to the global region (top of the viewport), which is
75
+ // where a confirmation belongs across a hand-built thread. (Inside <kai-chat>
76
+ // the chat owns feedback and targets ITSELF, so in-chat toasts still stay in-chat.)
77
+ });
78
+
79
+ // Imperative method API — `copy()` runs the exact path of the built-in copy
80
+ // action (`feedback.handleAction(msg, 'copy')`): writes the content to the
81
+ // clipboard, shows the transient copied-check on the bar, and emits
82
+ // `kai-message-action{action:'copy'}`.
83
+ expose({
84
+ /** Copy the message content to the clipboard and show the copied check. */
85
+ copy: () => feedback.handleAction(msg(), 'copy'),
86
+ });
61
87
 
62
88
  // Read declarative <kai-action> children from light DOM.
63
89
  // Shadow DOM with no <slot> suppresses them visually — they're invisible data carriers.
64
90
  const [slottedActions, setSlottedActions] = createSignal<import('../elements/chat-types').CustomAction[]>([]);
91
+ // Which composition slots (before-body / after-body / avatar) the consumer filled.
92
+ const [slots, setSlots] = createSignal<Record<string, boolean>>({});
65
93
  onMount(() => {
66
94
  const read = () => {
67
95
  const nodes = [...element.querySelectorAll('kai-action')];
@@ -71,6 +99,7 @@ defineWebComponent<Props, Events>('kai-message', {
71
99
  icon: n.getAttribute('icon') ?? undefined,
72
100
  tooltip: n.getAttribute('tooltip') ?? undefined,
73
101
  })));
102
+ setSlots(readSlots(element, MESSAGE_SLOTS));
74
103
  };
75
104
  read();
76
105
  const observer = new MutationObserver(read);
@@ -83,56 +112,58 @@ defineWebComponent<Props, Events>('kai-message', {
83
112
  (props.avatarSrc || props.avatarFallback
84
113
  ? { src: props.avatarSrc as string | undefined, fallback: props.avatarFallback as string | undefined }
85
114
  : undefined);
115
+ // Avatar rail state. `avatar="none"` omits the rail; a filled `slot="avatar"`
116
+ // REPLACES the built-in; otherwise the built-in renders when one resolves.
117
+ const noAvatar = () => props.avatar === 'none';
118
+ const hasAvatarSlot = () => !!slots()['avatar'];
119
+ // The rail shows when not suppressed and there's either a slot or a resolved avatar.
120
+ const showRail = () => !noAvatar() && (hasAvatarSlot() || !!avatar());
86
121
  const reveal = () => (props.actionsReveal === 'hover' ? 'hover' : 'always');
87
122
  // markdown: explicit prop/attribute wins; otherwise default by role.
88
123
  const markdownExplicit = () =>
89
124
  element.hasAttribute('markdown') || props.markdown === true || props.markdown === false;
90
125
  const useMarkdown = () => (markdownExplicit() ? flag('markdown') : !isUser());
91
126
 
127
+ const mergedActions = () => [...(msg().actions ?? []), ...slottedActions()];
92
128
  const body = () => (
93
- <>
94
- <Show when={msg().reasoning}>
95
- <Reasoning class="mb-2 w-full">
96
- <ReasoningTrigger>{msg().reasoning!.label ?? 'Reasoning'}</ReasoningTrigger>
97
- <ReasoningContent markdown>{msg().reasoning!.text}</ReasoningContent>
98
- </Reasoning>
99
- </Show>
100
- <For each={msg().tools ?? []}>
101
- {(tp) => <Tool toolPart={tp} class="mb-2 w-full" />}
102
- </For>
103
- <Show when={msg().attachments?.length}>
104
- <Attachments variant="inline" class={isUser() ? 'mb-2 justify-end' : 'mb-2'}>
105
- <For each={msg().attachments!}>
106
- {(att) => (
107
- <Attachment data={att}>
108
- <AttachmentPreview />
109
- <AttachmentInfo />
110
- </Attachment>
111
- )}
112
- </For>
113
- </Attachments>
114
- </Show>
115
- <MessageContent
116
- markdown={useMarkdown()}
117
- class={isUser()
118
- ? 'bg-muted text-primary max-w-[85%] rounded-2xl px-4 py-2'
119
- : 'bg-transparent p-0'}
120
- >
121
- {msg().content}
122
- </MessageContent>
123
- <Show when={(msg().actions?.length ?? 0) > 0 || slottedActions().length > 0}>
124
- <MessageActionBar
125
- actions={[...(msg().actions ?? []), ...slottedActions()]}
126
- reveal={reveal()}
127
- onAction={(action) => dispatch('kai-message-action', { messageId: msg().id, action })}
128
- />
129
- </Show>
130
- </>
129
+ <MessageBody
130
+ content={msg().content}
131
+ reasoning={msg().reasoning}
132
+ tools={msg().tools}
133
+ attachments={msg().attachments}
134
+ isUser={isUser()}
135
+ markdown={useMarkdown()}
136
+ actions={mergedActions()}
137
+ actionsReveal={reveal()}
138
+ activeFeedback={feedback.resolveFeedback(msg())}
139
+ copied={feedback.isCopied(msg().id)}
140
+ onAction={(action) => feedback.handleAction(msg(), action)}
141
+ beforeBody={slots()['before-body'] ? <slot name="before-body" /> : undefined}
142
+ afterBody={slots()['after-body'] ? <slot name="after-body" /> : undefined}
143
+ />
131
144
  );
132
145
 
133
146
  // Row carries `group` so a hover-revealed action bar fades in on row hover.
134
147
  const rowGroup = () => (reveal() === 'hover' ? 'group ' : '');
135
148
 
149
+ // The avatar rail: a filled `slot="avatar"` REPLACES the built-in MessageAvatar
150
+ // (the consumer owns that node, wrapped in `part="avatar"` so it's still
151
+ // styleable + consistent with the built-in part name).
152
+ const avatarRail = () => (
153
+ <Show
154
+ when={hasAvatarSlot()}
155
+ fallback={
156
+ <Show when={avatar()}>
157
+ {(av) => <MessageAvatar src={av().src ?? ''} alt={av().alt ?? ''} fallback={av().fallback} />}
158
+ </Show>
159
+ }
160
+ >
161
+ <div part="avatar" class="shrink-0">
162
+ <slot name="avatar" />
163
+ </div>
164
+ </Show>
165
+ );
166
+
136
167
  return (
137
168
  <ChatConfig
138
169
  proseSize={props.proseSize}
@@ -141,21 +172,19 @@ defineWebComponent<Props, Events>('kai-message', {
141
172
  portalMount={outer.portalMount()}
142
173
  >
143
174
  <Show
144
- when={avatar()}
175
+ when={showRail()}
145
176
  fallback={
146
177
  <Message class={`${rowGroup()}${isUser() ? 'flex-col items-end' : 'flex-col items-start'}`}>
147
178
  {body()}
148
179
  </Message>
149
180
  }
150
181
  >
151
- {(av) => (
152
- <Message class={rowGroup()}>
153
- <MessageAvatar src={av().src ?? ''} alt={av().alt ?? ''} fallback={av().fallback} />
154
- <div class={`flex min-w-0 flex-1 flex-col ${isUser() ? 'items-end' : 'items-start'}`}>
155
- {body()}
156
- </div>
157
- </Message>
158
- )}
182
+ <Message class={rowGroup()}>
183
+ {avatarRail()}
184
+ <div class={`flex min-w-0 flex-1 flex-col ${isUser() ? 'items-end' : 'items-start'}`}>
185
+ {body()}
186
+ </div>
187
+ </Message>
159
188
  </Show>
160
189
  </ChatConfig>
161
190
  );
@@ -1,6 +1,8 @@
1
1
  import { createSignal, onCleanup, onMount } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
3
  import { ModelSwitcher } from '../components/model-switcher';
4
+ import { wireDisclosure } from './disclosure';
5
+ import type { DropdownController } from '../ui/dropdown';
4
6
  import type { ModelOption } from '../types';
5
7
 
6
8
  interface Props extends Record<string, unknown> {
@@ -8,12 +10,22 @@ interface Props extends Record<string, unknown> {
8
10
  models: ModelOption[];
9
11
  /** The currently-selected model id. Defaults to the first model. */
10
12
  currentModel?: string;
13
+ /** Drive/observe the dropdown's open state (Shoelace-style: settable + reflected
14
+ * to the `open` attribute, the dropdown still self-manages on click/keyboard).
15
+ * Set `el.open = true`, or `<kai-model-switcher open>`; listen for `kai-open-change`. */
16
+ open?: boolean;
17
+ /** Initial open state on mount (uncontrolled seed). */
18
+ defaultOpen?: boolean;
19
+ /** Disable the trigger — click/keyboard and `show()` no longer open the dropdown. */
20
+ disabled?: boolean;
11
21
  }
12
22
 
13
23
  /** Events fired by `<kai-model-switcher>`. */
14
24
  interface Events {
15
25
  /** A model was selected. */
16
26
  'kai-model-change': { modelId: string };
27
+ /** The model dropdown opened or closed (by click, keyboard, Escape, outside-click, or a method). */
28
+ 'kai-open-change': { open: boolean };
17
29
  }
18
30
 
19
31
  /**
@@ -65,7 +77,18 @@ export function parseKaiModelElement(n: Element): ModelOption {
65
77
  defineWebComponent<Props, Events>('kai-model-switcher', {
66
78
  models: [],
67
79
  currentModel: undefined,
68
- }, (props, { dispatch, element }) => {
80
+ open: undefined,
81
+ defaultOpen: undefined,
82
+ disabled: undefined,
83
+ }, (props, ctx) => {
84
+ const { dispatch, element, flag } = ctx;
85
+ let api: DropdownController | undefined;
86
+
87
+ // The standard overlay surface: settable+reflecting `open`, kai-open-change,
88
+ // show/hide/toggle, disabled-gating. See ./disclosure. When <=1 model the inner
89
+ // Dropdown never mounts, so `api` stays undefined and these methods no-op.
90
+ wireDisclosure(ctx, () => api, () => props.open);
91
+
69
92
  // Read declarative <kai-model> children from light DOM.
70
93
  // Shadow DOM with no <slot> suppresses them visually — they're invisible data carriers.
71
94
  const [slottedModels, setSlottedModels] = createSignal<ModelOption[]>([]);
@@ -88,6 +111,9 @@ defineWebComponent<Props, Events>('kai-model-switcher', {
88
111
  models={allModels()}
89
112
  currentModelId={props.currentModel ?? allModels()[0]?.id ?? ''}
90
113
  onModelChange={(modelId) => dispatch('kai-model-change', { modelId })}
114
+ defaultOpen={flag('defaultOpen')}
115
+ disabled={flag('disabled')}
116
+ controllerRef={(a) => (api = a)}
91
117
  />
92
118
  );
93
119
  });
@@ -0,0 +1,87 @@
1
+ import { createSignal } from 'solid-js';
2
+ import { defineWebComponent } from './define';
3
+ import { Nav, type KaiNavItem } from '../ui/nav';
4
+
5
+ interface Props extends Record<string, unknown> {
6
+ /** The nav items. Set as a JS property (array, not an attribute). Each item may
7
+ * carry `children` (a collapsible group), a `status` dot, and trailing `meta`
8
+ * text. */
9
+ items?: KaiNavItem[];
10
+ /** Active item id (controlled). */
11
+ value?: string;
12
+ /** Initial active id when uncontrolled. */
13
+ defaultValue?: string;
14
+ /** Ids of group items collapsed on first render (groups default to expanded).
15
+ * Set as a JS property (array). */
16
+ defaultCollapsed?: string[];
17
+ }
18
+
19
+ interface Events {
20
+ /** A nav item was activated. */
21
+ 'kai-nav-select': { id: string };
22
+ /** A row's trailing `action` button was activated (not a select). `value` is
23
+ * the item id; `action` echoes the item's `{ icon, label }`. */
24
+ 'kai-nav-item-action': { value: string; action?: { icon: string; label: string } };
25
+ /** A `closable` row's trailing close button was activated (not a select).
26
+ * `value` is the item id. */
27
+ 'kai-nav-item-close': { value: string };
28
+ }
29
+
30
+ /**
31
+ * `<kai-nav>` — a vertical navigation list driven by a JSON `items` tree
32
+ * (id + label + optional leading `icon`, a trailing text `badge`, a trailing
33
+ * icon). Items may nest via `children` (a collapsible group with a disclosure
34
+ * chevron), carry a `status` dot (`{ tone, label?, pulse? }`), and a trailing
35
+ * `meta` string (e.g. a relative time). The active item is `value`; selecting a
36
+ * leaf fires `kai-nav-select` (group rows toggle expand/collapse instead).
37
+ *
38
+ * Items may also carry an `action` (`{ icon, label }`) or `closable: true`, which
39
+ * render a trailing button — firing `kai-nav-item-action` `{ value, action }` or
40
+ * `kai-nav-item-close` `{ value }` (never `kai-nav-select`). Style it via
41
+ * `::part(item-action)`.
42
+ *
43
+ * ```html
44
+ * <kai-nav default-value="home"></kai-nav>
45
+ * <script type="module">
46
+ * const nav = document.querySelector('kai-nav');
47
+ * nav.items = [
48
+ * { id: 'home', label: 'New task', icon: 'plus', trailing: 'pencil' },
49
+ * { id: 'acme', label: 'Acme', icon: 'folder', children: [
50
+ * { id: 't1', label: 'Refactor auth', status: { tone: 'info', label: 'Working', pulse: true }, meta: '2m' },
51
+ * { id: 't2', label: 'Landing page', status: { tone: 'success', label: 'Done' }, meta: '1d' },
52
+ * ] },
53
+ * { id: 'dispatch', label: 'Dispatch', icon: 'share', badge: 'Beta' },
54
+ * ];
55
+ * nav.addEventListener('kai-nav-select', (e) => console.log(e.detail.id));
56
+ * </script>
57
+ * ```
58
+ * Restyle via `::part(nav)` / `::part(item)` (active items carry `aria-current`),
59
+ * plus `::part(group)` / `::part(chevron)` / `::part(status)` / `::part(meta)`.
60
+ */
61
+ defineWebComponent<Props, Events>('kai-nav', {
62
+ items: undefined,
63
+ value: undefined,
64
+ defaultValue: undefined,
65
+ defaultCollapsed: undefined,
66
+ }, (props, { dispatch, expose }) => {
67
+ const [internal, setInternal] = createSignal(props.defaultValue as string | undefined);
68
+ const value = () => (props.value as string | undefined) ?? internal();
69
+ const select = (id: string) => { setInternal(id); dispatch('kai-nav-select', { id }); };
70
+
71
+ expose({
72
+ /** Activate an item by id (fires kai-nav-select). */
73
+ select: (id: string) => select(id),
74
+ });
75
+
76
+ return (
77
+ <Nav
78
+ items={props.items as KaiNavItem[] | undefined}
79
+ value={value()}
80
+ defaultCollapsed={props.defaultCollapsed as string[] | undefined}
81
+ onItemSelect={select}
82
+ onItemAction={(id, action) => dispatch('kai-nav-item-action', { value: id, action })}
83
+ onItemClose={(id) => dispatch('kai-nav-item-close', { value: id })}
84
+ part="nav"
85
+ />
86
+ );
87
+ });
@@ -0,0 +1,53 @@
1
+ import { Notice, noticeIconNode } from '../ui/notice';
2
+ import { defineWebComponent } from './define';
3
+
4
+ interface Props extends Record<string, unknown> {
5
+ /** `neutral` (default) · `info` · `warning` · `error` · `success`. Drives the
6
+ * leading icon's color and the a11y role (`alert` for errors, else `status`). */
7
+ severity?: 'neutral' | 'info' | 'warning' | 'error' | 'success';
8
+ /** Leading icon: omit for the severity default, `"none"` to hide it, or a named
9
+ * icon to override. */
10
+ icon?: string;
11
+ /** Show a dismiss (×) that hides the notice and emits `kai-dismiss`. */
12
+ dismissible?: boolean;
13
+ }
14
+
15
+ /** Events fired by `<kai-notice>`. */
16
+ interface Events {
17
+ /** The notice was dismissed via its × (it also hides itself). */
18
+ 'kai-dismiss': void;
19
+ }
20
+
21
+ /**
22
+ * `<kai-notice>` — a self-contained inline notice / alert. Put the message as
23
+ * light-DOM text and an optional `slot="action"` (e.g. a link); it carries the
24
+ * severity icon, the right a11y role, and an optional self-dismissing ×.
25
+ *
26
+ * It owns the notice box, not its placement — you position it in your own layout
27
+ * (above a composer, at the top of a panel, …).
28
+ *
29
+ * For a custom leading icon, slot any inline SVG via `slot="icon"` (it wins over
30
+ * the severity/`icon` default — the same escape hatch as `kai-button`).
31
+ *
32
+ * ```html
33
+ * <kai-notice severity="warning" dismissible>
34
+ * Claude Fable 5 is currently unavailable.
35
+ * <a slot="action" href="#">Learn more</a>
36
+ * </kai-notice>
37
+ * ```
38
+ */
39
+ defineWebComponent<Props, Events>('kai-notice', {
40
+ severity: 'neutral',
41
+ icon: undefined,
42
+ dismissible: false,
43
+ }, (props, { dispatch, flag }) => (
44
+ <Notice
45
+ severity={props.severity ?? 'neutral'}
46
+ iconSlot={<slot name="icon">{noticeIconNode(props.severity ?? 'neutral', props.icon)}</slot>}
47
+ dismissible={flag('dismissible')}
48
+ onDismiss={() => dispatch('kai-dismiss')}
49
+ action={<slot name="action" />}
50
+ >
51
+ <slot />
52
+ </Notice>
53
+ ));