@kitn.ai/ui 0.17.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 (494) hide show
  1. package/README.md +28 -5
  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 +37 -12
  9. package/dist/components/choice-card.d.ts +26 -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/file-tree.d.ts +15 -0
  19. package/dist/components/form.d.ts +34 -0
  20. package/dist/components/markdown.d.ts +3 -0
  21. package/dist/components/message.d.ts +12 -0
  22. package/dist/components/model-switcher.d.ts +7 -0
  23. package/dist/components/prompt-input.d.ts +13 -4
  24. package/dist/components/prompt-suggestion.d.ts +9 -1
  25. package/dist/components/reasoning.d.ts +14 -1
  26. package/dist/components/response-compare.d.ts +14 -0
  27. package/dist/components/screen.d.ts +46 -0
  28. package/dist/components/tasks-card.d.ts +49 -1
  29. package/dist/components/toast.d.ts +12 -2
  30. package/dist/components/tool-types.d.ts +10 -0
  31. package/dist/components/tool.d.ts +8 -8
  32. package/dist/components/voice-input.d.ts +27 -0
  33. package/dist/components/voice-output.d.ts +33 -0
  34. package/dist/core-C8fzo39E.js +12 -0
  35. package/dist/custom-elements.json +8392 -1860
  36. package/dist/elements/agent-card.d.ts +1 -0
  37. package/dist/elements/agent-card.js +1 -0
  38. package/dist/elements/artifact.js +1 -1
  39. package/dist/elements/attachments.js +1 -1
  40. package/dist/elements/autoloader.js +1 -1
  41. package/dist/elements/avatar.d.ts +1 -0
  42. package/dist/elements/avatar.js +1 -0
  43. package/dist/elements/badge.d.ts +1 -0
  44. package/dist/elements/badge.js +1 -0
  45. package/dist/elements/button.d.ts +1 -0
  46. package/dist/elements/button.js +1 -0
  47. package/dist/elements/card.js +1 -1
  48. package/dist/elements/cards.js +1 -1
  49. package/dist/elements/chain-of-thought.js +1 -1
  50. package/dist/elements/chat-scope-picker.js +1 -1
  51. package/dist/elements/chat-types.d.ts +47 -0
  52. package/dist/elements/chat-workspace.js +1 -1
  53. package/dist/elements/chat.js +1 -1
  54. package/dist/elements/checkpoint.js +1 -1
  55. package/dist/elements/choice.js +1 -1
  56. package/dist/elements/chunks/Icon-DLLBeLG5.js +1 -0
  57. package/dist/elements/chunks/action-icons-UB4V5FNq.js +1 -0
  58. package/dist/elements/chunks/arrow-left-C-gwlUmx.js +1 -0
  59. package/dist/elements/chunks/attachments-CgbErf1r.js +1 -0
  60. package/dist/elements/chunks/badge-DTQpgB6N.js +1 -0
  61. package/dist/elements/chunks/button-XDUM6lXs.js +1 -0
  62. package/dist/elements/chunks/card-CBlFZ-7I.js +1 -0
  63. package/dist/elements/chunks/chat-thread-BIhmqwNL.js +1 -0
  64. package/dist/elements/chunks/check-hGUoVIKb.js +1 -0
  65. package/dist/elements/chunks/chevron-down-DDoaSUtO.js +1 -0
  66. package/dist/elements/chunks/chevron-right-CdGEUakB.js +1 -0
  67. package/dist/elements/chunks/circle-BKAZdmzb.js +1 -0
  68. package/dist/elements/chunks/circle-check-CmYG-y3I.js +1 -0
  69. package/dist/elements/chunks/circle-x-DewgAEym.js +1 -0
  70. package/dist/elements/chunks/cn-CU7UAWzk.js +1 -0
  71. package/dist/elements/chunks/code-block-DedwxwFI.js +1 -0
  72. package/dist/elements/chunks/collapsible-FfgmTHtM.js +1 -0
  73. package/dist/elements/chunks/composer-Cfbw5HKT.js +65 -0
  74. package/dist/elements/chunks/context-DwJmxlRE.js +1 -0
  75. package/dist/elements/chunks/conversation-list-DsCQMfPq.js +1 -0
  76. package/dist/elements/chunks/default-input-BuqsoENC.js +1 -0
  77. package/dist/elements/chunks/define-rGsaWsLL.js +1 -0
  78. package/dist/elements/chunks/disclosure-CwoAkpMH.js +1 -0
  79. package/dist/elements/chunks/download-DJ06G3Bz.js +1 -0
  80. package/dist/elements/chunks/dropdown-BFg8ri_R.js +1 -0
  81. package/dist/elements/chunks/ellipsis-dlN6YvGw.js +1 -0
  82. package/dist/elements/chunks/external-link-DBX2lc_R.js +1 -0
  83. package/dist/elements/chunks/file-text-HfwUx4F9.js +1 -0
  84. package/dist/elements/chunks/file-tree-C6Toj71u.js +1 -0
  85. package/dist/elements/chunks/folder-MYuqa9Xp.js +1 -0
  86. package/dist/elements/chunks/hover-card-gE7iyXdW.js +1 -0
  87. package/dist/elements/chunks/icon-Vqz4ivrY.js +1 -0
  88. package/dist/elements/chunks/{index-CTBEJeo6.js → index-BCRhi84a.js} +1 -1
  89. package/dist/elements/chunks/info-B_toFS0l.js +1 -0
  90. package/dist/elements/chunks/input-gzbHYZvQ.js +1 -0
  91. package/dist/elements/chunks/kbd-n49c4KZm.js +1 -0
  92. package/dist/elements/chunks/link-CKPs9yM0.js +1 -0
  93. package/dist/elements/chunks/loader-q6MamGus.js +1 -0
  94. package/dist/elements/chunks/{markdown-CMTGx9r8.js → markdown-DBrcqq4S.js} +9 -9
  95. package/dist/elements/chunks/message-CTqaYI0s.js +1 -0
  96. package/dist/elements/chunks/message-feedback-Cvzm03w0.js +1 -0
  97. package/dist/elements/chunks/message-square-CUg9eRCi.js +1 -0
  98. package/dist/elements/chunks/minimize-2-l2klxP6K.js +1 -0
  99. package/dist/elements/chunks/model-switcher-CmyjiHO1.js +1 -0
  100. package/dist/elements/chunks/overlay-C8sOYqjT.js +1 -0
  101. package/dist/elements/chunks/paperclip-42Ia7xHD.js +1 -0
  102. package/dist/elements/chunks/progress-bar-tzKMWAwO.js +1 -0
  103. package/dist/elements/chunks/prompt-suggestion-D3F6vP_A.js +1 -0
  104. package/dist/elements/chunks/reasoning-BJNmmyov.js +1 -0
  105. package/dist/elements/chunks/resizable-BRsk19qI.js +1 -0
  106. package/dist/elements/chunks/rotate-cw-BgcggLHC.js +1 -0
  107. package/dist/elements/chunks/scroll-area-CgGbFFbT.js +1 -0
  108. package/dist/elements/chunks/separator-8hM4GdHE.js +1 -0
  109. package/dist/elements/chunks/settings-CaUIYOg-.js +1 -0
  110. package/dist/elements/chunks/settings-group-CYjOVIZQ.js +1 -0
  111. package/dist/elements/chunks/share-BTYM3Ddt.js +1 -0
  112. package/dist/elements/chunks/skeleton-DsTYrPUe.js +1 -0
  113. package/dist/elements/chunks/slots-DkZ-Cmha.js +1 -0
  114. package/dist/elements/chunks/star-9R3LBQ9n.js +1 -0
  115. package/dist/elements/chunks/store-CYl5Y0_u.js +1 -0
  116. package/dist/elements/chunks/text-shimmer-CaYGv8Se.js +1 -0
  117. package/dist/elements/chunks/textarea-NEr2SLcD.js +1 -0
  118. package/dist/elements/chunks/thumbs-up-DZYZkFfc.js +1 -0
  119. package/dist/elements/chunks/toast-store-ClxVZRcc.js +1 -0
  120. package/dist/elements/chunks/tool-CHZOmoe9.js +1 -0
  121. package/dist/elements/chunks/tooltip-WpHElELC.js +1 -0
  122. package/dist/elements/chunks/triangle-alert-BlS80PUg.js +1 -0
  123. package/dist/elements/chunks/use-card-resolution-VSVoxDeJ.js +1 -0
  124. package/dist/elements/chunks/video-DxTPZqT8.js +1 -0
  125. package/dist/elements/chunks/x-C1qtndxn.js +1 -0
  126. package/dist/elements/coachmark.d.ts +1 -0
  127. package/dist/elements/coachmark.js +1 -0
  128. package/dist/elements/code-block.js +1 -1
  129. package/dist/elements/command.d.ts +1 -0
  130. package/dist/elements/command.js +1 -0
  131. package/dist/elements/compare.js +1 -1
  132. package/dist/elements/composer.d.ts +1 -0
  133. package/dist/elements/composer.js +1 -0
  134. package/dist/elements/confirm-card.js +1 -1
  135. package/dist/elements/context-meter.js +1 -1
  136. package/dist/elements/conversation-list.js +1 -1
  137. package/dist/elements/css.d.ts +1 -0
  138. package/dist/elements/default-input.d.ts +51 -0
  139. package/dist/elements/define.d.ts +53 -0
  140. package/dist/elements/dialog.d.ts +1 -0
  141. package/dist/elements/dialog.js +1 -0
  142. package/dist/elements/disclosure.d.ts +37 -0
  143. package/dist/elements/editable-label.d.ts +1 -0
  144. package/dist/elements/editable-label.js +1 -0
  145. package/dist/elements/embed.js +1 -1
  146. package/dist/elements/empty.js +1 -1
  147. package/dist/elements/feedback-bar.js +1 -1
  148. package/dist/elements/file-tree.js +1 -1
  149. package/dist/elements/file-upload.js +1 -1
  150. package/dist/elements/form.js +1 -1
  151. package/dist/elements/hover-card.d.ts +1 -0
  152. package/dist/elements/hover-card.js +1 -0
  153. package/dist/elements/icon.d.ts +1 -0
  154. package/dist/elements/icon.js +1 -0
  155. package/dist/elements/image.js +1 -1
  156. package/dist/elements/input.d.ts +1 -0
  157. package/dist/elements/input.js +1 -0
  158. package/dist/elements/kbd.d.ts +1 -0
  159. package/dist/elements/kbd.js +1 -0
  160. package/dist/elements/link-preview.js +1 -1
  161. package/dist/elements/loader.js +1 -1
  162. package/dist/elements/markdown.js +1 -1
  163. package/dist/elements/menu.d.ts +1 -0
  164. package/dist/elements/menu.js +1 -0
  165. package/dist/elements/message-skills.js +1 -1
  166. package/dist/elements/message.js +1 -1
  167. package/dist/elements/model-switcher.js +1 -1
  168. package/dist/elements/nav.d.ts +1 -0
  169. package/dist/elements/nav.js +1 -0
  170. package/dist/elements/notice.d.ts +1 -0
  171. package/dist/elements/notice.js +1 -0
  172. package/dist/elements/pane-group.d.ts +1 -0
  173. package/dist/elements/pane-group.js +1 -0
  174. package/dist/elements/pane.d.ts +1 -0
  175. package/dist/elements/pane.js +1 -0
  176. package/dist/elements/popover.js +1 -1
  177. package/dist/elements/progress-bar.d.ts +1 -0
  178. package/dist/elements/progress-bar.js +1 -0
  179. package/dist/elements/prompt-dock.d.ts +1 -0
  180. package/dist/elements/prompt-dock.js +1 -0
  181. package/dist/elements/prompt-input.js +1 -1
  182. package/dist/elements/prompt-suggestions.js +1 -1
  183. package/dist/elements/reasoning.js +1 -1
  184. package/dist/elements/register-impl.d.ts +0 -0
  185. package/dist/elements/register.d.ts +13 -0
  186. package/dist/elements/remote.d.ts +1 -0
  187. package/dist/elements/remote.js +1 -0
  188. package/dist/elements/resizable.js +1 -1
  189. package/dist/elements/response-stream.js +2 -2
  190. package/dist/elements/screen.d.ts +1 -0
  191. package/dist/elements/screen.js +1 -0
  192. package/dist/elements/scroll-area.d.ts +1 -0
  193. package/dist/elements/scroll-area.js +1 -0
  194. package/dist/elements/scroll-button.js +1 -1
  195. package/dist/elements/search.d.ts +1 -0
  196. package/dist/elements/search.js +1 -0
  197. package/dist/elements/segmented.d.ts +1 -0
  198. package/dist/elements/segmented.js +1 -0
  199. package/dist/elements/separator.d.ts +1 -0
  200. package/dist/elements/separator.js +1 -0
  201. package/dist/elements/setting-item.d.ts +1 -0
  202. package/dist/elements/setting-item.js +1 -0
  203. package/dist/elements/settings-group.d.ts +1 -0
  204. package/dist/elements/settings-group.js +1 -0
  205. package/dist/elements/skeleton.d.ts +1 -0
  206. package/dist/elements/skeleton.js +1 -0
  207. package/dist/elements/slots.d.ts +176 -0
  208. package/dist/elements/source.js +1 -1
  209. package/dist/elements/status.d.ts +1 -0
  210. package/dist/elements/status.js +1 -0
  211. package/dist/elements/switch.js +1 -1
  212. package/dist/elements/tabs.d.ts +1 -0
  213. package/dist/elements/tabs.js +1 -0
  214. package/dist/elements/tasks.js +1 -1
  215. package/dist/elements/text-shimmer.js +1 -1
  216. package/dist/elements/thinking-bar.js +1 -1
  217. package/dist/elements/toast.js +1 -1
  218. package/dist/elements/tool.js +1 -1
  219. package/dist/elements/tooltip.d.ts +1 -0
  220. package/dist/elements/tooltip.js +1 -0
  221. package/dist/elements/voice-input.js +1 -1
  222. package/dist/elements/voice-output.d.ts +1 -0
  223. package/dist/elements/voice-output.js +1 -0
  224. package/dist/elements.d.ts +733 -58
  225. package/dist/engine-javascript-C1x7zo1_.js +141 -0
  226. package/dist/index.d.ts +3 -2
  227. package/dist/index.js +8256 -5703
  228. package/dist/kai.es.js +1 -0
  229. package/dist/llms/llms-full.txt +1146 -64
  230. package/dist/llms/llms.txt +4 -4
  231. package/dist/mcp.es.js +62 -7
  232. package/dist/primitives/composer-model.d.ts +22 -0
  233. package/dist/primitives/composer-triggers.d.ts +19 -0
  234. package/dist/primitives/create-kai-chat.d.ts +38 -0
  235. package/dist/primitives/toast-store.d.ts +32 -2
  236. package/dist/primitives/use-speech-recognition.d.ts +26 -0
  237. package/dist/react/index.d.ts +1085 -97
  238. package/dist/react/runtime.d.ts +9 -2
  239. package/dist/react/use-kai-chat.d.ts +41 -0
  240. package/dist/react.js +572 -193
  241. package/dist/register-impl-CYWGkgbI.js +141 -0
  242. package/dist/schemas/tasks.schema.json +2 -2
  243. package/dist/state/index.d.ts +4 -0
  244. package/dist/state/messages.d.ts +11 -0
  245. package/dist/state/stream.d.ts +22 -0
  246. package/dist/state/suggestions.d.ts +4 -0
  247. package/dist/state.js +117 -0
  248. package/dist/theme.tokens.css +87 -0
  249. package/dist/types.d.ts +4 -0
  250. package/dist/ui/agent-card.d.ts +61 -0
  251. package/dist/ui/button.d.ts +5 -2
  252. package/dist/ui/card.d.ts +61 -0
  253. package/dist/ui/collapsible.d.ts +15 -1
  254. package/dist/ui/command.d.ts +33 -0
  255. package/dist/ui/dialog.d.ts +42 -0
  256. package/dist/ui/dropdown.d.ts +95 -1
  257. package/dist/ui/editable-label.d.ts +26 -0
  258. package/dist/ui/hover-card.d.ts +13 -1
  259. package/dist/ui/icon.d.ts +18 -0
  260. package/dist/ui/input.d.ts +33 -0
  261. package/dist/ui/kbd.d.ts +21 -0
  262. package/dist/ui/nav.d.ts +62 -0
  263. package/dist/ui/notice.d.ts +31 -0
  264. package/dist/ui/overlay.d.ts +12 -0
  265. package/dist/ui/pane-grid.d.ts +58 -0
  266. package/dist/ui/pane-group.d.ts +75 -0
  267. package/dist/ui/pane.d.ts +78 -0
  268. package/dist/ui/popover.d.ts +11 -1
  269. package/dist/ui/progress-bar.d.ts +23 -0
  270. package/dist/ui/prompt-dock.d.ts +96 -0
  271. package/dist/ui/resizable.d.ts +12 -0
  272. package/dist/ui/scroll-area.d.ts +4 -0
  273. package/dist/ui/segmented.d.ts +28 -0
  274. package/dist/ui/settings-group.d.ts +32 -0
  275. package/dist/ui/skeleton.d.ts +12 -0
  276. package/dist/ui/stat.d.ts +16 -0
  277. package/dist/ui/status.d.ts +13 -0
  278. package/dist/ui/switch.d.ts +8 -1
  279. package/dist/ui/tabs.d.ts +35 -0
  280. package/dist/ui/tooltip.d.ts +19 -1
  281. package/frameworks/react/index.tsx +1042 -157
  282. package/frameworks/react/runtime.tsx +30 -1
  283. package/frameworks/react/use-kai-chat.tsx +87 -0
  284. package/llms-full.txt +1146 -64
  285. package/llms.txt +4 -4
  286. package/package.json +23 -8
  287. package/src/agent-tooling/mcp/manifest.ts +14 -0
  288. package/src/agent-tooling/mcp/tools/debug.ts +10 -6
  289. package/src/agent-tooling/mcp/tools/reference.ts +32 -0
  290. package/src/agent-tooling/mcp/tools/scaffold.ts +30 -1
  291. package/src/components/artifact.tsx +98 -13
  292. package/src/components/attachment-types.ts +13 -0
  293. package/src/components/attachments.tsx +4 -14
  294. package/src/components/card.tsx +109 -15
  295. package/src/components/chain-of-thought.tsx +210 -1
  296. package/src/components/chat-scope-picker.tsx +13 -3
  297. package/src/components/chat-thread.tsx +225 -116
  298. package/src/components/choice-card.tsx +103 -11
  299. package/src/components/coachmark.tsx +245 -0
  300. package/src/components/component-meta.json +691 -102
  301. package/src/components/composer-dom.ts +159 -0
  302. package/src/components/composer-highlight.ts +242 -0
  303. package/src/components/composer-history.ts +82 -0
  304. package/src/components/composer.tsx +979 -0
  305. package/src/components/confirm-card.tsx +54 -1
  306. package/src/components/conversation-item.tsx +69 -7
  307. package/src/components/conversation-list.tsx +134 -37
  308. package/src/components/file-tree.tsx +197 -47
  309. package/src/components/form-widgets.tsx +9 -7
  310. package/src/components/form.tsx +140 -17
  311. package/src/components/image.tsx +3 -5
  312. package/src/components/link-preview.tsx +5 -4
  313. package/src/components/markdown.tsx +5 -2
  314. package/src/components/message.tsx +23 -4
  315. package/src/components/model-switcher.tsx +19 -4
  316. package/src/components/prompt-input.tsx +46 -75
  317. package/src/components/prompt-suggestion.tsx +48 -16
  318. package/src/components/reasoning.tsx +29 -6
  319. package/src/components/response-compare.tsx +31 -2
  320. package/src/components/screen.tsx +176 -0
  321. package/src/components/tasks-card.tsx +342 -21
  322. package/src/components/toast.tsx +119 -31
  323. package/src/components/tool-types.ts +10 -0
  324. package/src/components/tool.tsx +22 -16
  325. package/src/components/voice-input.tsx +102 -19
  326. package/src/components/voice-output.tsx +202 -0
  327. package/src/elements/agent-card.tsx +67 -0
  328. package/src/elements/artifact.tsx +53 -4
  329. package/src/elements/attachments.tsx +1 -0
  330. package/src/elements/avatar.tsx +33 -0
  331. package/src/elements/badge.tsx +32 -0
  332. package/src/elements/button.tsx +126 -0
  333. package/src/elements/card-media.jpg +0 -0
  334. package/src/elements/card.tsx +124 -31
  335. package/src/elements/cards.tsx +81 -7
  336. package/src/elements/chain-of-thought.tsx +77 -32
  337. package/src/elements/chat-scope-picker.tsx +35 -8
  338. package/src/elements/chat-types.ts +2 -2
  339. package/src/elements/chat-workspace.tsx +153 -41
  340. package/src/elements/chat.tsx +45 -23
  341. package/src/elements/choice.tsx +71 -19
  342. package/src/elements/coachmark.tsx +90 -0
  343. package/src/elements/command.tsx +209 -0
  344. package/src/elements/compare.tsx +24 -2
  345. package/src/elements/compiled.css +1 -1
  346. package/src/elements/composer.tsx +151 -0
  347. package/src/elements/confirm-card.tsx +36 -11
  348. package/src/elements/conversation-list.tsx +80 -11
  349. package/src/elements/default-input.tsx +75 -53
  350. package/src/elements/define.tsx +47 -6
  351. package/src/elements/dialog.tsx +98 -0
  352. package/src/elements/disclosure.ts +73 -0
  353. package/src/elements/editable-label.tsx +125 -0
  354. package/src/elements/element-manifest.json +129 -1
  355. package/src/elements/element-meta.json +5562 -1336
  356. package/src/elements/element-types.d.ts +732 -57
  357. package/src/elements/file-tree.tsx +12 -2
  358. package/src/elements/file-upload.tsx +1 -1
  359. package/src/elements/form.tsx +54 -11
  360. package/src/elements/hover-card.tsx +80 -0
  361. package/src/elements/icon-names.json +48 -0
  362. package/src/elements/icon.tsx +41 -0
  363. package/src/elements/input.tsx +203 -0
  364. package/src/elements/kbd.tsx +45 -0
  365. package/src/elements/menu.tsx +217 -0
  366. package/src/elements/message.tsx +58 -11
  367. package/src/elements/model-switcher.tsx +27 -1
  368. package/src/elements/nav.tsx +87 -0
  369. package/src/elements/notice.tsx +53 -0
  370. package/src/elements/pane-group.tsx +119 -0
  371. package/src/elements/pane.tsx +129 -0
  372. package/src/elements/popover.tsx +39 -17
  373. package/src/elements/progress-bar.tsx +39 -0
  374. package/src/elements/prompt-dock.tsx +81 -0
  375. package/src/elements/prompt-input.tsx +112 -63
  376. package/src/elements/prompt-suggestions.tsx +25 -9
  377. package/src/elements/reasoning.tsx +30 -9
  378. package/src/elements/register-impl.ts +38 -3
  379. package/src/elements/register.ts +11 -3
  380. package/src/elements/resizable.tsx +48 -11
  381. package/src/elements/screen.tsx +90 -0
  382. package/src/elements/scroll-area.tsx +33 -0
  383. package/src/elements/search.tsx +180 -0
  384. package/src/elements/segmented.tsx +135 -0
  385. package/src/elements/separator.tsx +36 -0
  386. package/src/elements/setting-item.tsx +50 -0
  387. package/src/elements/settings-group.tsx +37 -0
  388. package/src/elements/skeleton.tsx +45 -0
  389. package/src/elements/slots.ts +607 -0
  390. package/src/elements/source.tsx +13 -6
  391. package/src/elements/status.tsx +42 -0
  392. package/src/elements/switch.tsx +89 -14
  393. package/src/elements/tabs.tsx +95 -0
  394. package/src/elements/tasks.tsx +70 -14
  395. package/src/elements/toast.tsx +17 -2
  396. package/src/elements/tool.tsx +43 -9
  397. package/src/elements/tooltip.tsx +85 -0
  398. package/src/elements/video-poster.jpg +0 -0
  399. package/src/elements/voice-input.tsx +66 -16
  400. package/src/elements/voice-output.tsx +69 -0
  401. package/src/index.ts +5 -2
  402. package/src/primitives/card-schemas/tasks.schema.json +2 -2
  403. package/src/primitives/composer-model.ts +49 -0
  404. package/src/primitives/composer-triggers.ts +35 -0
  405. package/src/primitives/create-kai-chat.ts +66 -0
  406. package/src/primitives/toast-store.ts +43 -2
  407. package/src/primitives/use-speech-recognition.ts +135 -0
  408. package/src/state/index.ts +6 -0
  409. package/src/state/messages.ts +36 -0
  410. package/src/state/stream.ts +92 -0
  411. package/src/state/suggestions.ts +9 -0
  412. package/src/types.ts +4 -0
  413. package/src/ui/agent-card.tsx +212 -0
  414. package/src/ui/button.tsx +16 -5
  415. package/src/ui/card.tsx +245 -0
  416. package/src/ui/collapsible.tsx +30 -4
  417. package/src/ui/command.tsx +99 -0
  418. package/src/ui/dialog.tsx +217 -0
  419. package/src/ui/dropdown.tsx +375 -13
  420. package/src/ui/editable-label.tsx +112 -0
  421. package/src/ui/hover-card.tsx +28 -5
  422. package/src/ui/icon.tsx +110 -0
  423. package/src/ui/input.tsx +132 -0
  424. package/src/ui/kbd.tsx +118 -0
  425. package/src/ui/nav.tsx +282 -0
  426. package/src/ui/notice.tsx +84 -0
  427. package/src/ui/overlay.tsx +108 -2
  428. package/src/ui/pane-grid.tsx +116 -0
  429. package/src/ui/pane-group.tsx +280 -0
  430. package/src/ui/pane.tsx +193 -0
  431. package/src/ui/popover.tsx +16 -2
  432. package/src/ui/progress-bar.tsx +83 -0
  433. package/src/ui/prompt-dock.tsx +145 -0
  434. package/src/ui/resizable.tsx +69 -1
  435. package/src/ui/scroll-area.tsx +14 -3
  436. package/src/ui/segmented.tsx +109 -0
  437. package/src/ui/settings-group.tsx +67 -0
  438. package/src/ui/skeleton.tsx +62 -5
  439. package/src/ui/stat.tsx +41 -0
  440. package/src/ui/status.tsx +48 -0
  441. package/src/ui/switch.tsx +49 -23
  442. package/src/ui/tabs.tsx +168 -0
  443. package/src/ui/tooltip.tsx +52 -8
  444. package/theme.css +113 -0
  445. package/dist/components/slash-command.d.ts +0 -15
  446. package/dist/elements/chunks/Icon-D_Zmwmwh.js +0 -1
  447. package/dist/elements/chunks/action-icons-PVfIvcuG.js +0 -1
  448. package/dist/elements/chunks/attachments-Dp6vqtrc.js +0 -1
  449. package/dist/elements/chunks/button-CKyYD9G4.js +0 -1
  450. package/dist/elements/chunks/card-Cjho-PYk.js +0 -1
  451. package/dist/elements/chunks/chat-thread-RT808iPf.js +0 -1
  452. package/dist/elements/chunks/check-CDYaMYrM.js +0 -1
  453. package/dist/elements/chunks/chevron-down-3SBiq8HF.js +0 -1
  454. package/dist/elements/chunks/chevron-right-k2UFlIVK.js +0 -1
  455. package/dist/elements/chunks/cn-Dogu6PbV.js +0 -1
  456. package/dist/elements/chunks/code-block-BYUmfFSd.js +0 -1
  457. package/dist/elements/chunks/collapsible-BiNwdOn6.js +0 -1
  458. package/dist/elements/chunks/context-18g6oi4J.js +0 -1
  459. package/dist/elements/chunks/conversation-list-D9Y0NVdo.js +0 -1
  460. package/dist/elements/chunks/default-input-CSAoYYMd.js +0 -1
  461. package/dist/elements/chunks/download-D8K0Je8r.js +0 -1
  462. package/dist/elements/chunks/dropdown-bUs2iTia.js +0 -1
  463. package/dist/elements/chunks/external-link-6mA0wxab.js +0 -1
  464. package/dist/elements/chunks/file-text-DnaYk3Dm.js +0 -1
  465. package/dist/elements/chunks/file-tree-CgtRLlxK.js +0 -1
  466. package/dist/elements/chunks/hover-card-CIGw62gP.js +0 -1
  467. package/dist/elements/chunks/link-BlGSeoPy.js +0 -1
  468. package/dist/elements/chunks/loader-DvhR4qa0.js +0 -1
  469. package/dist/elements/chunks/message-CDZwXjhL.js +0 -1
  470. package/dist/elements/chunks/message-feedback-CYx81QiA.js +0 -1
  471. package/dist/elements/chunks/model-switcher-O_tUhoOT.js +0 -1
  472. package/dist/elements/chunks/overlay-DydXYMQW.js +0 -1
  473. package/dist/elements/chunks/prompt-suggestion-ldlWV5kd.js +0 -1
  474. package/dist/elements/chunks/reasoning-2PUnHlmr.js +0 -1
  475. package/dist/elements/chunks/resizable-B5WNbSeb.js +0 -1
  476. package/dist/elements/chunks/star-t9tI-P0q.js +0 -1
  477. package/dist/elements/chunks/store-C6rIooZz.js +0 -1
  478. package/dist/elements/chunks/text-shimmer-uh9V_KUh.js +0 -1
  479. package/dist/elements/chunks/textarea-3nm6Ia9U.js +0 -1
  480. package/dist/elements/chunks/thumbs-up-BBtguGld.js +0 -1
  481. package/dist/elements/chunks/toast-store-D8cL3fWl.js +0 -1
  482. package/dist/elements/chunks/tool-GJ3vwp1U.js +0 -1
  483. package/dist/elements/chunks/tooltip-DwKAz4XR.js +0 -1
  484. package/dist/elements/chunks/triangle-alert-Ct1zt2JL.js +0 -1
  485. package/dist/elements/chunks/use-card-resolution-D-_0Alzy.js +0 -1
  486. package/dist/elements/chunks/video-mVYiM99-.js +0 -1
  487. package/dist/elements/chunks/x-CzxL27Ch.js +0 -1
  488. package/dist/kitn-chat.es.js +0 -1
  489. package/dist/register-JyTglR6m.js +0 -1
  490. package/dist/register-impl-C6wlSsts.js +0 -77
  491. package/src/components/slash-command.tsx +0 -232
  492. package/src/elements/framework-usage.json +0 -588
  493. /package/dist/{kitn-chat-provider.d.ts → kai-provider.d.ts} +0 -0
  494. /package/dist/{kitn-chat-provider.es.js → kai-provider.es.js} +0 -0
@@ -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 {
@@ -75,8 +86,6 @@ interface Events {
75
86
  'kai-search': Record<string, never>;
76
87
  /** The Mic / voice button was clicked. */
77
88
  'kai-voice': Record<string, never>;
78
- /** A slash command was chosen from the palette. */
79
- 'kai-slash-select': { command: SlashCommandItem };
80
89
  /** A suggestion chip was clicked (only in `suggestion-mode="fill"`). */
81
90
  'kai-suggestion-click': { value: string };
82
91
  }
@@ -87,20 +96,83 @@ defineWebComponent<Props, Events>('kai-workspace', {
87
96
  suggestions: undefined, suggestionMode: 'submit', proseSize: 'sm',
88
97
  codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
89
98
  models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
90
- search: false, voice: false, slashCommands: undefined, slashActiveIds: undefined, slashCompact: false,
91
- sidebarWidth: 22, sidebarMinWidth: 200, sidebarMaxWidth: 420,
92
- sidebarCollapsed: undefined, defaultSidebarCollapsed: undefined,
93
- }, (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
+
94
116
  // Controlled/uncontrolled collapse: `sidebarCollapsed` (when set) wins;
95
117
  // otherwise the element manages its own state, seeded from
96
- // `defaultSidebarCollapsed`. `toggle` always writes the internal value (a no-op
97
- // visually while controlled) and emits `kai-sidebar-toggle` so a controlling app
98
- // 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.
99
121
  const [collapsed, setCollapsed] = createControllableSignal(
100
122
  () => props.sidebarCollapsed as boolean | undefined,
101
123
  flag('defaultSidebarCollapsed'),
102
124
  );
103
- 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
+ });
104
176
 
105
177
  // Create the thread ONCE and reference the same node in both <Show> branches.
106
178
  // It's owned by this component root (not by a Show branch), so toggling the
@@ -115,8 +187,8 @@ defineWebComponent<Props, Events>('kai-workspace', {
115
187
  chatTitle={props.chatTitle as string | undefined} models={props.models as ModelOption[] | undefined}
116
188
  currentModel={props.currentModel as string | undefined} context={props.context as ChatThreadContextUsage | undefined}
117
189
  scrollButton={props.scrollButton !== false} search={flag('search')} voice={flag('voice')}
118
- slashCommands={props.slashCommands as SlashCommandItem[] | undefined}
119
- 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}
120
192
  onValueChange={(value) => dispatch('kai-value-change', { value })}
121
193
  onSubmit={(detail) => dispatch('kai-submit', detail)}
122
194
  onSuggestionClick={(value) => dispatch('kai-suggestion-click', { value })}
@@ -124,38 +196,78 @@ defineWebComponent<Props, Events>('kai-workspace', {
124
196
  onMessageAction={(detail) => dispatch('kai-message-action', detail)}
125
197
  onSearch={() => dispatch('kai-search', {})}
126
198
  onVoice={() => dispatch('kai-voice', {})}
127
- onSlashSelect={(command) => dispatch('kai-slash-select', { command })}
199
+ controllerRef={(c) => (controller = c)}
128
200
  />
129
201
  );
130
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
+
131
218
  return (
132
- <div class="h-full w-full overflow-hidden bg-background">
219
+ <div ref={rootEl} class="h-full w-full overflow-hidden bg-background">
133
220
  <Show
134
221
  when={!collapsed()}
135
222
  fallback={
136
- <div class="relative h-full">
137
- <Button
138
- variant="ghost" size="icon-sm" aria-label="Open sidebar"
139
- class="absolute left-2 top-2 z-10 rounded-full bg-card/80 shadow-sm backdrop-blur"
140
- onClick={toggle}
141
- >
142
- <PanelLeftOpen class="size-4" />
143
- </Button>
144
- {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>
145
235
  </div>
146
236
  }
147
237
  >
148
238
  <ResizablePanelGroup orientation="horizontal">
149
239
  <ResizablePanel defaultSize={props.sidebarWidth as number} data-min-size={String(props.sidebarMinWidth)} data-max-size={String(props.sidebarMaxWidth)}>
150
- <ConversationList
151
- groups={props.groups} conversations={props.conversations} activeId={props.activeId as string | undefined}
152
- onSelect={(id) => dispatch('kai-conversation-select', { id })}
153
- onNewChat={() => dispatch('kai-new-chat', {})}
154
- onToggleSidebar={toggle}
155
- />
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>
156
268
  </ResizablePanel>
157
269
  <ResizableHandle withHandle />
158
- <ResizablePanel>{threadEl}</ResizablePanel>
270
+ <ResizablePanel>{mainRegion}</ResizablePanel>
159
271
  </ResizablePanelGroup>
160
272
  </Show>
161
273
  </div>
@@ -1,20 +1,25 @@
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
25
  /** An action button on a message was clicked. `action` is the built-in name or
@@ -23,8 +28,6 @@ interface Events {
23
28
  'kai-message-action': { messageId: string; action: string; state?: 'on' | 'off' };
24
29
  /** The header model switcher changed. */
25
30
  'kai-model-change': { modelId: string };
26
- /** A slash command was chosen from the palette. */
27
- 'kai-slash-select': { command: SlashCommandItem };
28
31
  /** The Search button was clicked. */
29
32
  'kai-search': Record<string, never>;
30
33
  /** The Mic / voice button was clicked. */
@@ -36,27 +39,39 @@ defineWebComponent<Props, Events>('kai-chat', {
36
39
  suggestions: undefined, suggestionMode: 'submit', persistSuggestions: false, proseSize: 'sm',
37
40
  codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
38
41
  models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
39
- search: false, voice: false, slashCommands: undefined, slashActiveIds: undefined, slashCompact: false,
42
+ search: false, voice: false, triggers: undefined, kindIcons: undefined,
40
43
  actionsReveal: 'always',
41
- }, (props, { dispatch, flag, element }) => {
42
- // Detect consumer-projected header controls so the header opens for them even
43
- // without a title/models/context. Mirrors the <kai-model> light-DOM read pattern.
44
- const [hasHeaderStart, setHasHeaderStart] = createSignal(false);
45
- 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;
46
49
  onMount(() => {
47
- const read = () => {
48
- setHasHeaderStart(!!element.querySelector(':scope > [slot="header-start"]'));
49
- setHasHeaderEnd(!!element.querySelector(':scope > [slot="header-end"]'));
50
- };
50
+ const read = () => setSlots(readSlots(element, CHAT_SLOTS));
51
51
  read();
52
52
  const observer = new MutationObserver(read);
53
53
  observer.observe(element, { childList: true });
54
54
  onCleanup(() => observer.disconnect());
55
55
  });
56
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
+
57
72
  return (
58
73
  <ChatThread
59
- 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}
60
75
  loading={flag('loading')} suggestions={props.suggestions as string[] | undefined}
61
76
  suggestionMode={props.suggestionMode as 'submit' | 'fill'} persistSuggestions={flag('persistSuggestions')}
62
77
  proseSize={props.proseSize as ProseSize}
@@ -64,19 +79,26 @@ defineWebComponent<Props, Events>('kai-chat', {
64
79
  chatTitle={props.chatTitle as string | undefined} models={props.models as ModelOption[] | undefined}
65
80
  currentModel={props.currentModel as string | undefined} context={props.context as ChatThreadContextUsage | undefined}
66
81
  scrollButton={props.scrollButton !== false} search={flag('search')} voice={flag('voice')}
67
- slashCommands={props.slashCommands as SlashCommandItem[] | undefined}
68
- 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}
69
84
  actionsReveal={props.actionsReveal as 'always' | 'hover'}
70
85
  onValueChange={(value) => dispatch('kai-value-change', { value })}
71
86
  onSubmit={(detail) => dispatch('kai-submit', detail)}
87
+ onAttachmentsChange={(attachments) => dispatch('kai-attachments-change', { attachments })}
72
88
  onSuggestionClick={(value) => dispatch('kai-suggestion-click', { value })}
73
89
  onModelChange={(modelId) => dispatch('kai-model-change', { modelId })}
74
90
  onMessageAction={(detail) => dispatch('kai-message-action', detail)}
75
91
  onSearch={() => dispatch('kai-search', {})}
76
92
  onVoice={() => dispatch('kai-voice', {})}
77
- onSlashSelect={(command) => dispatch('kai-slash-select', { command })}
78
- headerStart={hasHeaderStart()}
79
- 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')}
80
102
  />
81
103
  );
82
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
  );
@@ -0,0 +1,90 @@
1
+ import { defineWebComponent } from './define';
2
+ import { Coachmark, type CoachmarkController } from '../components/coachmark';
3
+ import { wireDisclosure } from './disclosure';
4
+
5
+ interface Props extends Record<string, unknown> {
6
+ /** Drive/observe open state (Shoelace-style: settable + reflected to the `open`
7
+ * attribute; the element still self-manages). Set `el.open = true`, or
8
+ * `<kai-coachmark open>`; listen for `kai-open-change`. */
9
+ open?: boolean;
10
+ /** Initial open state on mount (uncontrolled seed). */
11
+ defaultOpen?: boolean;
12
+ /** The bold title. Named `headline` because `title` collides with the global
13
+ * `HTMLElement.title` attribute (it throws at registration). */
14
+ headline?: string;
15
+ /** A small badge pill beside the headline (e.g. "New"). */
16
+ badge?: string;
17
+ /** Floating placement relative to the anchor (default `bottom`). */
18
+ placement?: string;
19
+ /** Color tone: `primary` (default, theme accent), `info` (blue), `success`
20
+ * (green), `warning` (amber), or `error` (red) — reusing the kit's tool hues. */
21
+ tone?: 'primary' | 'info' | 'success' | 'warning' | 'error';
22
+ /** Render the arrow that points at the anchor (default `true`). Set
23
+ * `arrow="false"` for a plain bubble with no pointer. */
24
+ arrow?: boolean;
25
+ }
26
+
27
+ /** Events fired by `<kai-coachmark>`. */
28
+ interface Events {
29
+ /** The × dismiss button was pressed. The consumer records that this hint was
30
+ * seen so it won't show again. */
31
+ 'kai-dismiss': Record<string, never>;
32
+ /** The coachmark opened or closed (a method, the ×, or a driven `open`). */
33
+ 'kai-open-change': { open: boolean };
34
+ }
35
+
36
+ /**
37
+ * `<kai-coachmark>` — an anchored onboarding hint bubble with an arrow. It WRAPS
38
+ * a trigger (the default slot) and points a primary-colored bubble at it: a small
39
+ * `badge` pill, a bold `headline`, the `content` slot body, and a dismiss ×.
40
+ *
41
+ * ```html
42
+ * <kai-coachmark default-open headline="Cowork has a new home" badge="New">
43
+ * <button>Cowork</button>
44
+ * <span slot="content">Chat with Claude or switch to Cowork from here.</span>
45
+ * </kai-coachmark>
46
+ * <script type="module">
47
+ * document.querySelector('kai-coachmark')
48
+ * .addEventListener('kai-dismiss', () => localStorage.setItem('cowork-hint', 'seen'));
49
+ * </script>
50
+ * ```
51
+ *
52
+ * Open state is the standard disclosure surface: settable+reflecting `open`,
53
+ * `kai-open-change`, and `show()`/`hide()`/`toggle()`; seed with `default-open`.
54
+ * Parts: `bubble` · `arrow` · `badge` · `title` · `dismiss`.
55
+ */
56
+ defineWebComponent<Props, Events>('kai-coachmark', {
57
+ open: undefined,
58
+ defaultOpen: undefined,
59
+ headline: undefined,
60
+ badge: undefined,
61
+ placement: undefined,
62
+ tone: undefined,
63
+ arrow: true,
64
+ }, (props, ctx) => {
65
+ const { flag, dispatch } = ctx;
66
+ let api: CoachmarkController | undefined;
67
+
68
+ // The standard disclosure surface: settable+reflecting `open`, kai-open-change,
69
+ // show/hide/toggle. See ./disclosure. This is the SOLE emitter of kai-open-change.
70
+ wireDisclosure(ctx, () => api, () => props.open);
71
+
72
+ // headline/badge are scalar string props (NOT slots) — pass through directly so
73
+ // the component's own `Show when={…}` gating drives whether each region renders.
74
+ // The body is the `content` slot; an empty `<slot>` renders nothing.
75
+ return (
76
+ <Coachmark
77
+ defaultOpen={flag('defaultOpen')}
78
+ arrow={flag('arrow')}
79
+ placement={props.placement as never}
80
+ tone={props.tone as 'primary' | 'info' | 'success' | 'warning' | 'error' | undefined}
81
+ headline={props.headline as string | undefined}
82
+ badge={props.badge as string | undefined}
83
+ content={<slot name="content" />}
84
+ controllerRef={(a) => (api = a)}
85
+ onDismiss={() => dispatch('kai-dismiss', {})}
86
+ >
87
+ <slot />
88
+ </Coachmark>
89
+ );
90
+ });