@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
@@ -1,5 +1,7 @@
1
1
  import { defineWebComponent } from './define';
2
2
  import { ChatScopePicker } from '../components/chat-scope-picker';
3
+ import { wireDisclosure } from './disclosure';
4
+ import type { DropdownController } from '../ui/dropdown';
3
5
  import type { SearchFilters } from '../types';
4
6
 
5
7
  interface Props extends Record<string, unknown> {
@@ -9,12 +11,22 @@ interface Props extends Record<string, unknown> {
9
11
  availableTags: string[];
10
12
  /** The label shown on the trigger for the active scope. */
11
13
  currentLabel?: string;
14
+ /** Drive/observe the dropdown's open state (Shoelace-style: settable + reflected
15
+ * to the `open` attribute, the dropdown still self-manages on click/keyboard).
16
+ * Set `el.open = true`, or `<kai-scope-picker open>`; listen for `kai-open-change`. */
17
+ open?: boolean;
18
+ /** Initial open state on mount (uncontrolled seed). */
19
+ defaultOpen?: boolean;
20
+ /** Disable the trigger — click/keyboard and `show()` no longer open the dropdown. */
21
+ disabled?: boolean;
12
22
  }
13
23
 
14
24
  /** Events fired by `<kai-scope-picker>`. */
15
25
  interface Events {
16
26
  /** A scope was chosen (`undefined` filters = "All Content"). */
17
27
  'kai-scope-change': { filters: SearchFilters | undefined };
28
+ /** The scope dropdown opened or closed (by click, keyboard, Escape, outside-click, or a method). */
29
+ 'kai-open-change': { open: boolean };
18
30
  }
19
31
 
20
32
  /**
@@ -26,11 +38,26 @@ defineWebComponent<Props, Events>('kai-scope-picker', {
26
38
  availableAuthors: [],
27
39
  availableTags: [],
28
40
  currentLabel: 'All Content',
29
- }, (props, { dispatch }) => (
30
- <ChatScopePicker
31
- currentLabel={props.currentLabel ?? 'All Content'}
32
- availableAuthors={props.availableAuthors}
33
- availableTags={props.availableTags}
34
- onScopeChange={(filters) => dispatch('kai-scope-change', { filters })}
35
- />
36
- ));
41
+ open: undefined,
42
+ defaultOpen: undefined,
43
+ disabled: undefined,
44
+ }, (props, ctx) => {
45
+ const { dispatch, flag } = ctx;
46
+ let api: DropdownController | undefined;
47
+
48
+ // The standard overlay surface: settable+reflecting `open`, kai-open-change,
49
+ // show/hide/toggle, disabled-gating. See ./disclosure.
50
+ wireDisclosure(ctx, () => api, () => props.open);
51
+
52
+ return (
53
+ <ChatScopePicker
54
+ currentLabel={props.currentLabel ?? 'All Content'}
55
+ availableAuthors={props.availableAuthors}
56
+ availableTags={props.availableTags}
57
+ onScopeChange={(filters) => dispatch('kai-scope-change', { filters })}
58
+ defaultOpen={flag('defaultOpen')}
59
+ disabled={flag('disabled')}
60
+ controllerRef={(a) => (api = a)}
61
+ />
62
+ );
63
+ });
@@ -1,9 +1,12 @@
1
- import type { ToolPart } from '../components/tool';
2
- import type { AttachmentData } from '../components/attachments';
1
+ import type { ToolPart } from '../components/tool-types';
2
+ import type { AttachmentData } from '../components/attachment-types';
3
3
 
4
4
  /** The five built-in action buttons (each carries its own curated icon + label). */
5
5
  export type ChatMessageAction = 'copy' | 'like' | 'dislike' | 'regenerate' | 'edit';
6
6
 
7
+ /** A like/dislike feedback vote on an assistant message. */
8
+ export type FeedbackVote = 'like' | 'dislike';
9
+
7
10
  /** A host-defined action button. `icon` is a curated registry name (see
8
11
  * `src/ui/action-icons.ts`); unknown/absent icons render label-only. */
9
12
  export interface CustomAction {
@@ -39,4 +42,8 @@ export interface ChatMessage {
39
42
  actions?: (ChatMessageAction | CustomAction)[];
40
43
  /** Optional speaker avatar shown to the left of the message column. */
41
44
  avatar?: AvatarData;
45
+ /** Controlled feedback vote. When set, it wins over the facade's internal
46
+ * optimistic state (`m.feedback ?? feedbackMap[m.id]`), so a host that
47
+ * persists votes can re-hydrate them. */
48
+ feedback?: FeedbackVote;
42
49
  }
@@ -1,13 +1,12 @@
1
- import { Show } from 'solid-js';
1
+ import { Show, createSignal, onMount, onCleanup } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
3
  import { createControllableSignal } from '../primitives/controllable';
4
- import { ChatThread, type ChatThreadContextUsage } from '../components/chat-thread';
5
- import { ConversationList } from '../components/conversation-list';
4
+ import { readSlots, WORKSPACE_SLOTS } from './slots';
5
+ import { ChatThread, type ChatThreadContextUsage, type ChatThreadController } from '../components/chat-thread';
6
+ import { ConversationList, CollapsedRail } from '../components/conversation-list';
6
7
  import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from '../ui/resizable';
7
- import { Button } from '../ui/button';
8
- import { PanelLeftOpen } from 'lucide-solid';
9
8
  import type { AttachmentData } from '../components/attachments';
10
- import type { SlashCommandItem } from '../components/slash-command';
9
+ import type { TriggerDef } from '../components/composer';
11
10
  import type { ChatMessage } from './chat-types';
12
11
  import type { ProseSize } from '../primitives/chat-config';
13
12
  import type { ModelOption, ConversationGroup, ConversationSummary } from '../types';
@@ -36,12 +35,13 @@ interface Props extends Record<string, unknown> {
36
35
  scrollButton?: boolean;
37
36
  search?: boolean;
38
37
  voice?: boolean;
39
- slashCommands?: SlashCommandItem[];
40
- slashActiveIds?: string[];
41
- slashCompact?: boolean;
42
- /** Sidebar default width as a percent of the workspace (default 22). */
38
+ /** Rich entity triggers (`/` skills, `@` agents/plugins) forwarded to the input. */
39
+ triggers?: TriggerDef[];
40
+ /** Default icon per entity kind (kind → image src) forwarded to the input. */
41
+ kindIcons?: Record<string, string>;
42
+ /** Sidebar default width as a percent of the workspace (default 26). */
43
43
  sidebarWidth?: number;
44
- /** Sidebar min width in px (default 200). */
44
+ /** Sidebar min width in px (default 240). */
45
45
  sidebarMinWidth?: number;
46
46
  /** Sidebar max width in px (default 420). */
47
47
  sidebarMaxWidth?: number;
@@ -52,6 +52,17 @@ interface Props extends Record<string, unknown> {
52
52
  /** Initial collapsed state when uncontrolled (default false). Use the
53
53
  * `default-sidebar-collapsed` attribute to start collapsed in plain HTML. */
54
54
  defaultSidebarCollapsed?: boolean;
55
+ /** Auto-collapse the rail when the workspace's own width drops below this many
56
+ * px, and re-expand when it grows back above. Uncontrolled only (it never
57
+ * fights an app-driven `sidebarCollapsed`); omit to disable. Fires
58
+ * `kai-sidebar-toggle`. Attribute: `collapse-below`. */
59
+ collapseBelow?: number;
60
+ /** Render Recents as dense single-line rows (a leading dot + title, no count). */
61
+ compact?: boolean;
62
+ /** Suppress the built-in ConversationList so the `sidebar-header` slot owns the
63
+ * whole rail flex region (for apps that supply their own rail nav). Default
64
+ * false. Attribute: `no-conversations`. */
65
+ noConversations?: boolean;
55
66
  }
56
67
 
57
68
  interface Events {
@@ -67,14 +78,14 @@ interface Events {
67
78
  'kai-value-change': { value: string };
68
79
  /** The header model switcher changed. */
69
80
  'kai-model-change': { modelId: string };
70
- /** An action button on a message was clicked. */
71
- 'kai-message-action': { messageId: string; action: string };
81
+ /** An action button on a message was clicked. `state` is present only for the
82
+ * toggleable feedback votes: `'on'` when a like/dislike is set, `'off'` when
83
+ * re-tapped to clear. */
84
+ 'kai-message-action': { messageId: string; action: string; state?: 'on' | 'off' };
72
85
  /** The Search button was clicked. */
73
86
  'kai-search': Record<string, never>;
74
87
  /** The Mic / voice button was clicked. */
75
88
  'kai-voice': Record<string, never>;
76
- /** A slash command was chosen from the palette. */
77
- 'kai-slash-select': { command: SlashCommandItem };
78
89
  /** A suggestion chip was clicked (only in `suggestion-mode="fill"`). */
79
90
  'kai-suggestion-click': { value: string };
80
91
  }
@@ -85,20 +96,83 @@ defineWebComponent<Props, Events>('kai-workspace', {
85
96
  suggestions: undefined, suggestionMode: 'submit', proseSize: 'sm',
86
97
  codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
87
98
  models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
88
- search: false, voice: false, slashCommands: undefined, slashActiveIds: undefined, slashCompact: false,
89
- sidebarWidth: 22, sidebarMinWidth: 200, sidebarMaxWidth: 420,
90
- sidebarCollapsed: undefined, defaultSidebarCollapsed: undefined,
91
- }, (props, { dispatch, flag }) => {
99
+ search: false, voice: false, triggers: undefined, kindIcons: undefined,
100
+ sidebarWidth: 26, sidebarMinWidth: 240, sidebarMaxWidth: 420,
101
+ sidebarCollapsed: undefined, defaultSidebarCollapsed: undefined, collapseBelow: undefined, compact: undefined,
102
+ noConversations: undefined,
103
+ }, (props, { dispatch, flag, expose, element }) => {
104
+ // Which injection slots the consumer has filled. A bare <slot> is always a
105
+ // truthy JSX node, so we render each region wrapper ONLY when readSlots reports
106
+ // projected light-DOM content (re-read on childList mutation).
107
+ const [slots, setSlots] = createSignal<Record<string, boolean>>({});
108
+ onMount(() => {
109
+ const read = () => setSlots(readSlots(element, WORKSPACE_SLOTS));
110
+ read();
111
+ const observer = new MutationObserver(read);
112
+ observer.observe(element, { childList: true });
113
+ onCleanup(() => observer.disconnect());
114
+ });
115
+
92
116
  // Controlled/uncontrolled collapse: `sidebarCollapsed` (when set) wins;
93
117
  // otherwise the element manages its own state, seeded from
94
- // `defaultSidebarCollapsed`. `toggle` always writes the internal value (a no-op
95
- // visually while controlled) and emits `kai-sidebar-toggle` so a controlling app
96
- // can update its own state.
118
+ // `defaultSidebarCollapsed`. `setCollapsedTo` always writes the internal value (a
119
+ // no-op visually while controlled) and emits `kai-sidebar-toggle` so a controlling
120
+ // app can update its own state.
97
121
  const [collapsed, setCollapsed] = createControllableSignal(
98
122
  () => props.sidebarCollapsed as boolean | undefined,
99
123
  flag('defaultSidebarCollapsed'),
100
124
  );
101
- const toggle = () => { const next = !collapsed(); setCollapsed(next); dispatch('kai-sidebar-toggle', { collapsed: next }); };
125
+ const setCollapsedTo = (next: boolean) => { setCollapsed(next); dispatch('kai-sidebar-toggle', { collapsed: next }); };
126
+ const toggle = () => setCollapsedTo(!collapsed());
127
+
128
+ // Responsive auto-collapse. When `collapseBelow` is set, a ResizeObserver on the
129
+ // workspace root collapses the rail once the workspace's own width drops below
130
+ // it and re-expands above it. Uncontrolled only — bail while `sidebarCollapsed`
131
+ // is set so we never fight an app-driven collapse. `autoCollapsed` tracks whether
132
+ // WE collapsed it, so a user's manual expand isn't auto-undone on the next tick.
133
+ let rootEl!: HTMLDivElement;
134
+ let autoCollapsed = false;
135
+ onMount(() => {
136
+ if (typeof ResizeObserver === 'undefined') return;
137
+ const ro = new ResizeObserver((entries) => {
138
+ const below = props.collapseBelow as number | undefined;
139
+ if (below == null || props.sidebarCollapsed !== undefined) return;
140
+ const width = entries[0]?.contentRect.width ?? rootEl.clientWidth;
141
+ const isBelow = width < below;
142
+ if (isBelow && !collapsed()) {
143
+ autoCollapsed = true;
144
+ setCollapsedTo(true);
145
+ } else if (!isBelow && collapsed() && autoCollapsed) {
146
+ autoCollapsed = false;
147
+ setCollapsedTo(false);
148
+ }
149
+ });
150
+ ro.observe(rootEl);
151
+ onCleanup(() => ro.disconnect());
152
+ });
153
+
154
+ // Imperative method API. The sidebar methods drive the same collapse path as the
155
+ // in-UI toggle (named *Sidebar to avoid the `sidebarCollapsed` prop accessor).
156
+ // The thread methods delegate to the embedded ChatThread's controller, captured
157
+ // once below — the thread node is shared across both <Show> branches, so a single
158
+ // controllerRef is stable across collapse/expand.
159
+ let controller: ChatThreadController | undefined;
160
+ expose({
161
+ /** Collapse/expand the conversation sidebar and fire `kai-sidebar-toggle`. */
162
+ toggleSidebar: () => toggle(),
163
+ /** Force the conversation sidebar collapsed (fires `kai-sidebar-toggle`). */
164
+ collapseSidebar: () => setCollapsedTo(true),
165
+ /** Force the conversation sidebar expanded (fires `kai-sidebar-toggle`). */
166
+ expandSidebar: () => setCollapsedTo(false),
167
+ /** Focus the thread's composer. */
168
+ focus: (options?: FocusOptions) => controller?.focus(options),
169
+ /** Clear the thread draft + staged attachments. */
170
+ clear: () => controller?.clear(),
171
+ /** Submit the current thread draft programmatically (fires `kai-submit`). */
172
+ send: () => controller?.send(),
173
+ /** Scroll the thread to the newest message. */
174
+ scrollToBottom: (behavior?: ScrollBehavior) => controller?.scrollToBottom(behavior),
175
+ });
102
176
 
103
177
  // Create the thread ONCE and reference the same node in both <Show> branches.
104
178
  // It's owned by this component root (not by a Show branch), so toggling the
@@ -113,8 +187,8 @@ defineWebComponent<Props, Events>('kai-workspace', {
113
187
  chatTitle={props.chatTitle as string | undefined} models={props.models as ModelOption[] | undefined}
114
188
  currentModel={props.currentModel as string | undefined} context={props.context as ChatThreadContextUsage | undefined}
115
189
  scrollButton={props.scrollButton !== false} search={flag('search')} voice={flag('voice')}
116
- slashCommands={props.slashCommands as SlashCommandItem[] | undefined}
117
- slashActiveIds={props.slashActiveIds as string[] | undefined} slashCompact={flag('slashCompact')}
190
+ triggers={props.triggers as TriggerDef[] | undefined}
191
+ kindIcons={props.kindIcons as Record<string, string> | undefined}
118
192
  onValueChange={(value) => dispatch('kai-value-change', { value })}
119
193
  onSubmit={(detail) => dispatch('kai-submit', detail)}
120
194
  onSuggestionClick={(value) => dispatch('kai-suggestion-click', { value })}
@@ -122,38 +196,78 @@ defineWebComponent<Props, Events>('kai-workspace', {
122
196
  onMessageAction={(detail) => dispatch('kai-message-action', detail)}
123
197
  onSearch={() => dispatch('kai-search', {})}
124
198
  onVoice={() => dispatch('kai-voice', {})}
125
- onSlashSelect={(command) => dispatch('kai-slash-select', { command })}
199
+ controllerRef={(c) => (controller = c)}
126
200
  />
127
201
  );
128
202
 
203
+ // The main region: an optional top-placed `main-header` band above the thread.
204
+ // Shared across both collapse branches (the thread node is the same instance).
205
+ const mainRegion = (
206
+ <div class="flex h-full flex-col overflow-hidden">
207
+ <Show when={slots()['main-header']}>
208
+ <div class="shrink-0 border-b border-border"><slot name="main-header" /></div>
209
+ </Show>
210
+ <div class="min-h-0 flex-1">
211
+ <Show when={slots()['main']} fallback={threadEl}>
212
+ <slot name="main" />
213
+ </Show>
214
+ </div>
215
+ </div>
216
+ );
217
+
129
218
  return (
130
- <div class="h-full w-full overflow-hidden bg-background">
219
+ <div ref={rootEl} class="h-full w-full overflow-hidden bg-background">
131
220
  <Show
132
221
  when={!collapsed()}
133
222
  fallback={
134
- <div class="relative h-full">
135
- <Button
136
- variant="ghost" size="icon-sm" aria-label="Open sidebar"
137
- class="absolute left-2 top-2 z-10 rounded-full bg-card/80 shadow-sm backdrop-blur"
138
- onClick={toggle}
139
- >
140
- <PanelLeftOpen class="size-4" />
141
- </Button>
142
- {threadEl}
223
+ <div class="flex h-full">
224
+ {/* Collapsed: the reopen control lives in its OWN thin rail column
225
+ (matching the sidebar's bg-surface) rather than floating over the
226
+ content. The previous `absolute` overlay sat on top of a
227
+ `main-header`'s leading title — see the t3code/codex/chatgpt apps,
228
+ all of which fill that slot — so it both overlapped the header and
229
+ competed with any in-header toggle. A dedicated column never
230
+ overlaps and reads as a collapsed sidebar. */}
231
+ <div class="flex w-11 shrink-0 flex-col items-center border-r border-border bg-surface pt-2.5">
232
+ <CollapsedRail onExpand={toggle} class="bg-transparent shadow-none backdrop-blur-none" />
233
+ </div>
234
+ <div class="min-w-0 flex-1">{mainRegion}</div>
143
235
  </div>
144
236
  }
145
237
  >
146
238
  <ResizablePanelGroup orientation="horizontal">
147
239
  <ResizablePanel defaultSize={props.sidebarWidth as number} data-min-size={String(props.sidebarMinWidth)} data-max-size={String(props.sidebarMaxWidth)}>
148
- <ConversationList
149
- groups={props.groups} conversations={props.conversations} activeId={props.activeId as string | undefined}
150
- onSelect={(id) => dispatch('kai-conversation-select', { id })}
151
- onNewChat={() => dispatch('kai-new-chat', {})}
152
- onToggleSidebar={toggle}
153
- />
240
+ {/* The rail: an optional injected header above the list and footer
241
+ below it (upgrade card / Design trigger / user menu). Carries a
242
+ subtle, theme-aware default background (bg-surface), exposed as
243
+ ::part(sidebar) so a consumer can override it. The inner list is
244
+ made transparent so the part background reads uniformly. */}
245
+ <div part="sidebar" class="flex h-full flex-col overflow-hidden bg-surface">
246
+ <Show when={slots()['sidebar-header']}>
247
+ {/* When `no-conversations` suppresses the built-in list, the
248
+ projected header owns the whole rail flex region; otherwise it
249
+ sits as a fixed band above the list. */}
250
+ <div class={flag('noConversations') ? 'min-h-0 flex-1' : 'shrink-0'}><slot name="sidebar-header" /></div>
251
+ </Show>
252
+ <Show when={!flag('noConversations')}>
253
+ <div class="min-h-0 flex-1">
254
+ <ConversationList
255
+ class="bg-transparent"
256
+ groups={props.groups} conversations={props.conversations} activeId={props.activeId as string | undefined}
257
+ compact={flag('compact')}
258
+ onSelect={(id) => dispatch('kai-conversation-select', { id })}
259
+ onNewChat={() => dispatch('kai-new-chat', {})}
260
+ onToggleSidebar={toggle}
261
+ />
262
+ </div>
263
+ </Show>
264
+ <Show when={slots()['sidebar-footer']}>
265
+ <div class="shrink-0"><slot name="sidebar-footer" /></div>
266
+ </Show>
267
+ </div>
154
268
  </ResizablePanel>
155
269
  <ResizableHandle withHandle />
156
- <ResizablePanel>{threadEl}</ResizablePanel>
270
+ <ResizablePanel>{mainRegion}</ResizablePanel>
157
271
  </ResizablePanelGroup>
158
272
  </Show>
159
273
  </div>
@@ -1,28 +1,33 @@
1
- import { createSignal, onCleanup, onMount } from 'solid-js';
1
+ import { createEffect, createSignal, onCleanup, onMount } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
- import { ChatThread, type ChatThreadProps, type ChatThreadContextUsage } from '../components/chat-thread';
3
+ import { CHAT_SLOTS, readSlots } from './slots';
4
+ import { ChatThread, type ChatThreadProps, type ChatThreadContextUsage, type ChatThreadController } from '../components/chat-thread';
4
5
  import type { AttachmentData } from '../components/attachments';
5
- import type { SlashCommandItem } from '../components/slash-command';
6
+ import type { TriggerDef } from '../components/composer';
7
+ import type { ComposerDoc } from '../primitives/composer-model';
6
8
  import type { ProseSize } from '../primitives/chat-config';
7
9
  import type { ModelOption } from '../types';
8
10
 
9
11
  type Props = Omit<ChatThreadProps,
10
- 'class' | 'onValueChange' | 'onSubmit' | 'onSuggestionClick' | 'onModelChange'
11
- | 'onMessageAction' | 'onSearch' | 'onVoice' | 'onSlashSelect'> & Record<string, unknown>;
12
+ 'class' | 'onValueChange' | 'onSubmit' | 'onAttachmentsChange' | 'onSuggestionClick' | 'onModelChange'
13
+ | 'onMessageAction' | 'onSearch' | 'onVoice' | 'controllerRef'> & Record<string, unknown>;
12
14
 
13
15
  interface Events {
14
16
  /** User submitted a message. */
15
17
  'kai-submit': { value: string; attachments: AttachmentData[] };
16
18
  /** Fired on every input change. */
17
19
  'kai-value-change': { value: string };
20
+ /** The staged attachments changed (file added or removed). Carries the full
21
+ * current list so a consumer can react in real time. */
22
+ 'kai-attachments-change': { attachments: AttachmentData[] };
18
23
  /** A suggestion chip was clicked (only in `suggestion-mode="fill"`). */
19
24
  'kai-suggestion-click': { value: string };
20
- /** An action button on a message was clicked. `action` is the built-in name or custom id. */
21
- 'kai-message-action': { messageId: string; action: string };
25
+ /** An action button on a message was clicked. `action` is the built-in name or
26
+ * custom id. `state` is present only for the toggleable feedback votes:
27
+ * `'on'` when a like/dislike is set, `'off'` when re-tapped to clear. */
28
+ 'kai-message-action': { messageId: string; action: string; state?: 'on' | 'off' };
22
29
  /** The header model switcher changed. */
23
30
  'kai-model-change': { modelId: string };
24
- /** A slash command was chosen from the palette. */
25
- 'kai-slash-select': { command: SlashCommandItem };
26
31
  /** The Search button was clicked. */
27
32
  'kai-search': Record<string, never>;
28
33
  /** The Mic / voice button was clicked. */
@@ -34,27 +39,39 @@ defineWebComponent<Props, Events>('kai-chat', {
34
39
  suggestions: undefined, suggestionMode: 'submit', persistSuggestions: false, proseSize: 'sm',
35
40
  codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
36
41
  models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
37
- search: false, voice: false, slashCommands: undefined, slashActiveIds: undefined, slashCompact: false,
42
+ search: false, voice: false, triggers: undefined, kindIcons: undefined,
38
43
  actionsReveal: 'always',
39
- }, (props, { dispatch, flag, element }) => {
40
- // Detect consumer-projected header controls so the header opens for them even
41
- // without a title/models/context. Mirrors the <kai-model> light-DOM read pattern.
42
- const [hasHeaderStart, setHasHeaderStart] = createSignal(false);
43
- const [hasHeaderEnd, setHasHeaderEnd] = createSignal(false);
44
+ }, (props, { dispatch, flag, element, expose }) => {
45
+ // Slot detection is driven by the CHAT_SLOTS registry (single source of truth)
46
+ // so slot names never drift between the view, the facade, and the docs.
47
+ const [slots, setSlots] = createSignal<Record<string, boolean>>({});
48
+ const slot = (name: string) => slots()[name] === true;
44
49
  onMount(() => {
45
- const read = () => {
46
- setHasHeaderStart(!!element.querySelector(':scope > [slot="header-start"]'));
47
- setHasHeaderEnd(!!element.querySelector(':scope > [slot="header-end"]'));
48
- };
50
+ const read = () => setSlots(readSlots(element, CHAT_SLOTS));
49
51
  read();
50
52
  const observer = new MutationObserver(read);
51
53
  observer.observe(element, { childList: true });
52
54
  onCleanup(() => observer.disconnect());
53
55
  });
54
56
 
57
+ // Reflect streaming state to a host attribute so slotted composer/notice CSS
58
+ // can react without reading internals (e.g. :host([loading]) ::slotted(...)).
59
+ createEffect(() => { element.toggleAttribute('loading', flag('loading')); });
60
+
61
+ // Imperative method API — forward the chat-thread controller onto the host
62
+ // (focus the composer, clear it, send programmatically, scroll the thread).
63
+ let controller: ChatThreadController | undefined;
64
+ expose({
65
+ focus: (options?: FocusOptions) => controller?.focus(options),
66
+ blur: () => (element.shadowRoot?.activeElement as HTMLElement | null)?.blur(),
67
+ clear: () => controller?.clear(),
68
+ send: () => controller?.send(),
69
+ scrollToBottom: (behavior?: ScrollBehavior) => controller?.scrollToBottom(behavior),
70
+ });
71
+
55
72
  return (
56
73
  <ChatThread
57
- messages={props.messages} value={props.value as string | undefined} placeholder={props.placeholder as string}
74
+ messages={props.messages} value={props.value as string | ComposerDoc | undefined} placeholder={props.placeholder as string}
58
75
  loading={flag('loading')} suggestions={props.suggestions as string[] | undefined}
59
76
  suggestionMode={props.suggestionMode as 'submit' | 'fill'} persistSuggestions={flag('persistSuggestions')}
60
77
  proseSize={props.proseSize as ProseSize}
@@ -62,19 +79,26 @@ defineWebComponent<Props, Events>('kai-chat', {
62
79
  chatTitle={props.chatTitle as string | undefined} models={props.models as ModelOption[] | undefined}
63
80
  currentModel={props.currentModel as string | undefined} context={props.context as ChatThreadContextUsage | undefined}
64
81
  scrollButton={props.scrollButton !== false} search={flag('search')} voice={flag('voice')}
65
- slashCommands={props.slashCommands as SlashCommandItem[] | undefined}
66
- slashActiveIds={props.slashActiveIds as string[] | undefined} slashCompact={flag('slashCompact')}
82
+ triggers={props.triggers as TriggerDef[] | undefined}
83
+ kindIcons={props.kindIcons as Record<string, string> | undefined}
67
84
  actionsReveal={props.actionsReveal as 'always' | 'hover'}
68
85
  onValueChange={(value) => dispatch('kai-value-change', { value })}
69
86
  onSubmit={(detail) => dispatch('kai-submit', detail)}
87
+ onAttachmentsChange={(attachments) => dispatch('kai-attachments-change', { attachments })}
70
88
  onSuggestionClick={(value) => dispatch('kai-suggestion-click', { value })}
71
89
  onModelChange={(modelId) => dispatch('kai-model-change', { modelId })}
72
90
  onMessageAction={(detail) => dispatch('kai-message-action', detail)}
73
91
  onSearch={() => dispatch('kai-search', {})}
74
92
  onVoice={() => dispatch('kai-voice', {})}
75
- onSlashSelect={(command) => dispatch('kai-slash-select', { command })}
76
- headerStart={hasHeaderStart()}
77
- headerEnd={hasHeaderEnd()}
93
+ controllerRef={(c) => (controller = c)}
94
+ headerStart={slot('header-start')}
95
+ headerEnd={slot('header-end')}
96
+ headerFull={slot('header')}
97
+ sidebar={slot('sidebar')}
98
+ empty={slot('empty')}
99
+ composer={slot('composer')}
100
+ composerActions={slot('composer-actions')}
101
+ footer={slot('footer')}
78
102
  />
79
103
  );
80
104
  });
@@ -1,5 +1,5 @@
1
1
  import { defineWebComponent } from './define';
2
- import { ChoiceCard, type ChoiceCardData } from '../components/choice-card';
2
+ import { ChoiceCard, type ChoiceCardData, type ChoiceController } from '../components/choice-card';
3
3
  import type { CardResolution } from '../primitives/card-contract';
4
4
 
5
5
  interface Props extends Record<string, unknown> {
@@ -14,35 +14,87 @@ interface Props extends Record<string, unknown> {
14
14
  /** Set when the user resolved this card; renders the read-only view. Property:
15
15
  * `el.resolution = { kind:'action', action:'…' }`. */
16
16
  resolution?: Record<string, unknown>;
17
+ /** Controlled selection — the selected option id. When set, the consumer owns
18
+ * the current pick (RadioGroup `value`). Attribute: `value`. */
19
+ value?: string;
20
+ /** Option id to pre-select on mount (uncontrolled seed). Attribute: `default-value`. */
21
+ defaultValue?: string;
22
+ /** Disable the whole radiogroup + Submit (e.g. while the agent is busy).
23
+ * Attribute: `disabled`. */
24
+ disabled?: boolean;
25
+ }
26
+
27
+ /** Events fired by `<kai-choice>`. (The terminal submit/dismiss/reopen flow is
28
+ * emitted via the bubbling `kai-card` contract event — listen for `kai-card`.) */
29
+ interface Events {
30
+ /** The selection changed BEFORE submit (a row click or the `select()` method).
31
+ * Distinct from the terminal `action` verb on the `kai-card` contract event. */
32
+ 'kai-value-change': { value: string };
17
33
  }
18
34
 
19
35
  /**
20
36
  * `<kai-choice>` — a single-select **"pick one of N rich options"** card (set via the
21
37
  * `data` property): a prompt + a radiogroup of list rows. Clicking a row **selects** it
22
- * (no emit); the **Submit** button below then emits the Card contract's **`action`** verb
23
- * up a bubbling **`kai-card`** CustomEvent (`{ kind:'action', cardId, action: option.id,
24
- * payload? }`) and resolves the card so the same pick can't double-fire. An optional
25
- * `allowOther` free-text escape appends a selectable "Other…" row that reveals an inline
26
- * input; the same Submit emits `action:'__other__'` with `{ text }`. Also emits `ready` on
27
- * mount and `error` for a malformed definition (inline error). Routes through a
28
- * `CardProvider` when present, else the bubbling `kai-card` event. Isolated in Shadow DOM;
29
- * theme-aware via the shared tokens.
38
+ * (no emit, fires `kai-value-change`); the **Submit** button below then emits the Card
39
+ * contract's **`action`** verb up a bubbling **`kai-card`** CustomEvent (`{ kind:'action',
40
+ * cardId, action: option.id, payload? }`) and resolves the card so the same pick can't
41
+ * double-fire. An optional `allowOther` free-text escape appends a selectable "Other…" row
42
+ * that reveals an inline input; the same Submit emits `action:'__other__'` with `{ text }`.
43
+ * Also emits `ready` on mount and `error` for a malformed definition (inline error). Routes
44
+ * through a `CardProvider` when present, else the bubbling `kai-card` event. Isolated in
45
+ * Shadow DOM; theme-aware via the shared tokens.
46
+ *
47
+ * Supports controlled selection (`value`), an uncontrolled seed (`defaultValue`), a
48
+ * group-level `disabled`, and instance methods `focus()`/`select(id)`/`send()`/
49
+ * `dismiss()`/`reopen()`.
30
50
  */
31
- defineWebComponent<Props>(
51
+ defineWebComponent<Props, Events>(
32
52
  'kai-choice',
33
53
  {
34
54
  data: undefined,
35
55
  cardId: undefined,
36
56
  heading: undefined,
37
57
  resolution: undefined,
58
+ value: undefined,
59
+ defaultValue: undefined,
60
+ disabled: undefined,
61
+ },
62
+ (props, { element, dispatch, flag, expose }) => {
63
+ // Pattern C: the ChoiceCard owns selection/submit/dismiss state and hands up a
64
+ // controller; the facade captures it and exposes delegating methods. The card's
65
+ // own paths still fire (select → kai-value-change; send → kai-card `action`;
66
+ // dismiss/reopen → kai-card `dismiss`/`reopen`).
67
+ let controller: ChoiceController | undefined;
68
+ expose({
69
+ /** Focus the radiogroup roving tab stop (or the Other input when selected). */
70
+ focus: (options?: FocusOptions) => controller?.focus(options),
71
+ /** Select an option by id locally — no emit, fires kai-value-change (same as
72
+ * a row click). Lets a consumer pre-highlight or drive selection externally. */
73
+ select: (optionId: string) => controller?.select(optionId),
74
+ /** Submit the current selection — emits the `action` verb on kai-card and
75
+ * resolves the card (single-shot). Named `send`, not `submit`, per the shared
76
+ * vocabulary. */
77
+ send: () => controller?.send(),
78
+ /** Trigger the dismiss path — emits `dismiss` on kai-card and optimistically
79
+ * collapses the card to its re-openable stub. */
80
+ dismiss: () => controller?.dismiss(),
81
+ /** Re-open a dismissed card from its stub — emits `reopen` on kai-card. */
82
+ reopen: () => controller?.reopen(),
83
+ });
84
+
85
+ return (
86
+ <ChoiceCard
87
+ data={props.data as ChoiceCardData | undefined}
88
+ cardId={props.cardId ?? (element.id || 'kai-choice')}
89
+ heading={props.heading}
90
+ resolution={props.resolution as CardResolution | undefined}
91
+ value={props.value}
92
+ defaultValue={props.defaultValue}
93
+ disabled={flag('disabled')}
94
+ onValueChange={(value) => dispatch('kai-value-change', { value })}
95
+ controllerRef={(c) => (controller = c)}
96
+ hostElement={element}
97
+ />
98
+ );
38
99
  },
39
- (props, { element }) => (
40
- <ChoiceCard
41
- data={props.data as ChoiceCardData | undefined}
42
- cardId={props.cardId ?? (element.id || 'kai-choice')}
43
- heading={props.heading}
44
- resolution={props.resolution as CardResolution | undefined}
45
- hostElement={element}
46
- />
47
- ),
48
100
  );