@kitn.ai/ui 0.17.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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-C2LTALdM.js +1 -0
  57. package/dist/elements/chunks/action-icons-Dtl8Ox5D.js +1 -0
  58. package/dist/elements/chunks/arrow-left-GbBceGBE.js +1 -0
  59. package/dist/elements/chunks/attachments-DLJcWCDV.js +1 -0
  60. package/dist/elements/chunks/badge-BTNZTODL.js +1 -0
  61. package/dist/elements/chunks/button-DBDZebGr.js +1 -0
  62. package/dist/elements/chunks/card-YfCyI4fH.js +1 -0
  63. package/dist/elements/chunks/chat-thread-Dz2qbzvI.js +1 -0
  64. package/dist/elements/chunks/check-fhmRksq_.js +1 -0
  65. package/dist/elements/chunks/chevron-down-DcRg1aRU.js +1 -0
  66. package/dist/elements/chunks/chevron-right-ChzBcNJ-.js +1 -0
  67. package/dist/elements/chunks/circle-B4fTe9v6.js +1 -0
  68. package/dist/elements/chunks/circle-check-CJV-3Rem.js +1 -0
  69. package/dist/elements/chunks/circle-x-pDtzlghQ.js +1 -0
  70. package/dist/elements/chunks/cn-CU7UAWzk.js +1 -0
  71. package/dist/elements/chunks/code-block-DZ6mz6vs.js +1 -0
  72. package/dist/elements/chunks/collapsible-CWUAShMC.js +1 -0
  73. package/dist/elements/chunks/composer-BZyPU6gD.js +65 -0
  74. package/dist/elements/chunks/context-Cx6eQA_G.js +1 -0
  75. package/dist/elements/chunks/conversation-list-C4xTQSpT.js +1 -0
  76. package/dist/elements/chunks/default-input-BZcwyKcP.js +1 -0
  77. package/dist/elements/chunks/define-CNSKFZCd.js +1 -0
  78. package/dist/elements/chunks/disclosure-BcBs--Jf.js +1 -0
  79. package/dist/elements/chunks/download-BDQwcFav.js +1 -0
  80. package/dist/elements/chunks/dropdown-wgs8xCJZ.js +1 -0
  81. package/dist/elements/chunks/ellipsis-CUiEJ6R1.js +1 -0
  82. package/dist/elements/chunks/external-link-DJUmC7g2.js +1 -0
  83. package/dist/elements/chunks/file-text-DOYfYvrh.js +1 -0
  84. package/dist/elements/chunks/file-tree-DQzNQrbr.js +1 -0
  85. package/dist/elements/chunks/folder-DBDUBANz.js +1 -0
  86. package/dist/elements/chunks/hover-card-BQGdGAQ3.js +1 -0
  87. package/dist/elements/chunks/icon-CAyRqVrg.js +1 -0
  88. package/dist/elements/chunks/{index-CTBEJeo6.js → index-BCRhi84a.js} +1 -1
  89. package/dist/elements/chunks/info-DBQl-m6e.js +1 -0
  90. package/dist/elements/chunks/input-DZD67EvW.js +1 -0
  91. package/dist/elements/chunks/kbd-DbyVrlnU.js +1 -0
  92. package/dist/elements/chunks/link-vko7AttA.js +1 -0
  93. package/dist/elements/chunks/loader-Cg6rO8tQ.js +1 -0
  94. package/dist/elements/chunks/{markdown-CMTGx9r8.js → markdown-n3Xbj3PR.js} +9 -9
  95. package/dist/elements/chunks/message-CgKytiSB.js +1 -0
  96. package/dist/elements/chunks/message-feedback-Ds3-US0e.js +1 -0
  97. package/dist/elements/chunks/message-square-MmRkvc-M.js +1 -0
  98. package/dist/elements/chunks/minimize-2-3kCdE0q3.js +1 -0
  99. package/dist/elements/chunks/model-switcher-BMtXGwLU.js +1 -0
  100. package/dist/elements/chunks/overlay-B1-MBI6h.js +1 -0
  101. package/dist/elements/chunks/paperclip-DDEfmkHc.js +1 -0
  102. package/dist/elements/chunks/progress-bar-Dwbiyv3s.js +1 -0
  103. package/dist/elements/chunks/prompt-suggestion-9lvgFcEa.js +1 -0
  104. package/dist/elements/chunks/reasoning-DzHWsdAJ.js +1 -0
  105. package/dist/elements/chunks/resizable-Bq_eHxUm.js +1 -0
  106. package/dist/elements/chunks/rotate-cw-jpisOdOV.js +1 -0
  107. package/dist/elements/chunks/scroll-area-g5Ze3K6f.js +1 -0
  108. package/dist/elements/chunks/separator-Bmjc5XyX.js +1 -0
  109. package/dist/elements/chunks/settings-Cz1bMJP9.js +1 -0
  110. package/dist/elements/chunks/settings-group-9imY3kRA.js +1 -0
  111. package/dist/elements/chunks/share-BdenF0wQ.js +1 -0
  112. package/dist/elements/chunks/skeleton-Pjc5jiaY.js +1 -0
  113. package/dist/elements/chunks/slots-DkZ-Cmha.js +1 -0
  114. package/dist/elements/chunks/star-DY6z1UUH.js +1 -0
  115. package/dist/elements/chunks/store-th4VyJXM.js +1 -0
  116. package/dist/elements/chunks/text-shimmer-CEi-tlXr.js +1 -0
  117. package/dist/elements/chunks/textarea-CboigarR.js +1 -0
  118. package/dist/elements/chunks/thumbs-up-BR33KLfA.js +1 -0
  119. package/dist/elements/chunks/toast-store-BEMda0fv.js +1 -0
  120. package/dist/elements/chunks/tool-TMued3WO.js +1 -0
  121. package/dist/elements/chunks/tooltip-Cft_Rxiw.js +1 -0
  122. package/dist/elements/chunks/triangle-alert-B07fX3Q8.js +1 -0
  123. package/dist/elements/chunks/use-card-resolution-M36zVciB.js +1 -0
  124. package/dist/elements/chunks/video-MKp3LmNT.js +1 -0
  125. package/dist/elements/chunks/x-Ckwicf6g.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 +8255 -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-cKscku5m.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 +77 -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 +31 -10
  287. package/src/agent-tooling/mcp/manifest.ts +14 -0
  288. package/src/agent-tooling/mcp/tools/debug.ts +11 -7
  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 +249 -0
  300. package/src/components/component-meta.json +699 -110
  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 +341 -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 +2 -2
  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 +87 -7
  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 +218 -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 +117 -0
  429. package/src/ui/pane-group.tsx +291 -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
@@ -0,0 +1,217 @@
1
+ import { For, Show } from 'solid-js';
2
+ import { MoreHorizontal } from 'lucide-solid';
3
+ import {
4
+ Dropdown, DropdownTrigger, DropdownContent, DropdownItem,
5
+ DropdownSeparator, DropdownLabel, DropdownCheckboxItem, DropdownRadioItem,
6
+ DropdownSub, DropdownSubTrigger, DropdownSubContent,
7
+ type DropdownController,
8
+ } from '../ui/dropdown';
9
+ import { renderIcon } from '../ui/icon';
10
+ import { Kbd } from '../ui/kbd';
11
+ import { cn } from '../utils/cn';
12
+ import { defineWebComponent } from './define';
13
+ import { wireDisclosure } from './disclosure';
14
+
15
+ export interface KaiMenuItem {
16
+ /** Emitted in `kai-select` for actionable items. */
17
+ id?: string;
18
+ label?: string;
19
+ /** Named icon (e.g. "paperclip"), image URL / data-URI, or plain text. */
20
+ icon?: string;
21
+ /** e.g. '⌘U' — shown right-aligned, muted. */
22
+ shortcut?: string;
23
+ /** Presence ⇒ a checkbox item (role=menuitemcheckbox). With `radioGroup` set,
24
+ * marks the SELECTED radio item in that group instead. */
25
+ checked?: boolean;
26
+ /** Membership in a single-select group (role=menuitemradio). Items sharing a
27
+ * `radioGroup` are mutually exclusive — the one with `checked: true` shows the
28
+ * checkmark; selecting one emits `{ id, radioGroup }` so the consumer moves
29
+ * the checkmark (the consumer owns state, like checkbox items). */
30
+ radioGroup?: string;
31
+ disabled?: boolean;
32
+ /** A divider (ignores other fields). */
33
+ separator?: boolean;
34
+ /** A non-interactive section label (uses `label`). */
35
+ heading?: boolean;
36
+ /** ⇒ a submenu. */
37
+ items?: KaiMenuItem[];
38
+ }
39
+
40
+ interface Props extends Record<string, unknown> {
41
+ /** Tree of menu items. Set as a JS property — not an HTML attribute. */
42
+ items?: KaiMenuItem[];
43
+ /** Optional placement hint (unused by the underlying Dropdown which always
44
+ * positions bottom-start, kept for future extension). */
45
+ placement?: string;
46
+ /** Built-in trigger: leading icon (a named icon like `"plus"`, an image
47
+ * URL/data-URI, or text). Use this instead of slotting `slot="trigger"` for
48
+ * the common case — a slotted trigger overrides it. */
49
+ triggerIcon?: string;
50
+ /** Built-in trigger: a text label (e.g. `"High"`). */
51
+ triggerLabel?: string;
52
+ /** Built-in trigger: a trailing icon (e.g. `"chevron-down"` for a select look). */
53
+ triggerIconTrailing?: string;
54
+ /** Accessible name for an icon-only trigger (no visible label). */
55
+ label?: string;
56
+ /** Drive/observe open state (Shoelace-style: settable + reflected to the `open`
57
+ * attribute, the menu still self-manages on click/keyboard). Set `el.open = true`,
58
+ * or `<kai-menu open>`; listen for `kai-open-change`. */
59
+ open?: boolean;
60
+ /** Initial open state on mount (uncontrolled seed). */
61
+ defaultOpen?: boolean;
62
+ /** Disable the trigger — click/keyboard and `show()` no longer open the menu. */
63
+ disabled?: boolean;
64
+ }
65
+
66
+ interface Events {
67
+ /**
68
+ * Fired when the user selects a leaf item.
69
+ * - Plain items: `{ id }`.
70
+ * - Checkbox items: `{ id, checked }` where `checked` is the NEW state.
71
+ * - Radio items: `{ id, radioGroup }` — the consumer marks `id` as the selected
72
+ * one in `radioGroup` and clears the others.
73
+ */
74
+ 'kai-select': { id: string; checked?: boolean; radioGroup?: string };
75
+ /** The menu opened or closed (by click, keyboard, Escape, outside-click, or a method). */
76
+ 'kai-open-change': { open: boolean };
77
+ }
78
+
79
+ /**
80
+ * `<kai-menu>` — a cascading action menu driven by a JSON items-tree.
81
+ *
82
+ * Set the `items` property in JavaScript (array, not attribute). The trigger
83
+ * is slotted — put your icon/button content in `slot="trigger"`:
84
+ *
85
+ * ```html
86
+ * <kai-menu>
87
+ * <button slot="trigger" aria-label="Open menu">+</button>
88
+ * </kai-menu>
89
+ * <script type="module">
90
+ * import '@kitn.ai/ui/elements';
91
+ * const menu = document.querySelector('kai-menu');
92
+ * menu.items = [
93
+ * { heading: true, label: 'Actions' },
94
+ * { id: 'attach', label: 'Add files', icon: 'paperclip', shortcut: 'Mod+U' },
95
+ * ];
96
+ * menu.addEventListener('kai-select', (e) => console.log(e.detail));
97
+ * </script>
98
+ * ```
99
+ */
100
+ defineWebComponent<Props, Events>('kai-menu', {
101
+ items: undefined,
102
+ placement: undefined,
103
+ triggerIcon: undefined,
104
+ triggerLabel: undefined,
105
+ triggerIconTrailing: undefined,
106
+ label: undefined,
107
+ open: undefined,
108
+ defaultOpen: undefined,
109
+ disabled: undefined,
110
+ }, (props, ctx) => {
111
+ const { dispatch, flag } = ctx;
112
+ let api: DropdownController | undefined;
113
+
114
+ // The standard overlay surface: settable+reflecting `open`, kai-open-change,
115
+ // show/hide/toggle, disabled-gating. See ./disclosure.
116
+ wireDisclosure(ctx, () => api, () => props.open);
117
+
118
+ function renderItems(items: KaiMenuItem[]) {
119
+ return (
120
+ <For each={items}>
121
+ {(item) => {
122
+ if (item.separator) {
123
+ return <DropdownSeparator />;
124
+ }
125
+ if (item.heading) {
126
+ return <DropdownLabel>{item.label}</DropdownLabel>;
127
+ }
128
+ if (item.items && item.items.length > 0) {
129
+ return (
130
+ <DropdownSub>
131
+ <DropdownSubTrigger>
132
+ <Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
133
+ {item.label}
134
+ </DropdownSubTrigger>
135
+ <DropdownSubContent>
136
+ {renderItems(item.items)}
137
+ </DropdownSubContent>
138
+ </DropdownSub>
139
+ );
140
+ }
141
+ if (item.radioGroup !== undefined) {
142
+ return (
143
+ <DropdownRadioItem
144
+ checked={item.checked}
145
+ disabled={item.disabled}
146
+ onSelect={() => {
147
+ if (item.id) dispatch('kai-select', { id: item.id, radioGroup: item.radioGroup });
148
+ }}
149
+ >
150
+ <Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
151
+ {item.label}
152
+ </DropdownRadioItem>
153
+ );
154
+ }
155
+ if (item.checked !== undefined) {
156
+ return (
157
+ <DropdownCheckboxItem
158
+ checked={item.checked}
159
+ disabled={item.disabled}
160
+ onSelect={() => {
161
+ if (item.id) dispatch('kai-select', { id: item.id, checked: !item.checked });
162
+ }}
163
+ >
164
+ <Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
165
+ {item.label}
166
+ </DropdownCheckboxItem>
167
+ );
168
+ }
169
+ return (
170
+ <DropdownItem
171
+ disabled={item.disabled}
172
+ onSelect={() => { if (item.id) dispatch('kai-select', { id: item.id }); }}
173
+ >
174
+ <Show when={item.icon}>{renderIcon(item.icon, { imgClass: 'mr-2 size-4 shrink-0', spanClass: 'mr-2 flex h-4 w-4 shrink-0 items-center justify-center text-sm' })}</Show>
175
+ {item.label}
176
+ <Show when={item.shortcut}>
177
+ <span part="shortcut" class="ml-auto pl-4 text-muted-foreground">
178
+ <Kbd keys={item.shortcut!} platform="auto" size="sm" />
179
+ </span>
180
+ </Show>
181
+ </DropdownItem>
182
+ );
183
+ }}
184
+ </For>
185
+ );
186
+ }
187
+
188
+ return (
189
+ <Dropdown
190
+ defaultOpen={flag('defaultOpen')}
191
+ disabled={flag('disabled')}
192
+ controllerRef={(a) => (api = a)}
193
+ >
194
+ <DropdownTrigger
195
+ class={cn(
196
+ 'inline-flex items-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
197
+ props.triggerLabel
198
+ ? 'gap-1.5 px-2 py-1.5 text-sm font-medium text-muted-foreground hover:bg-accent hover:text-foreground'
199
+ : 'justify-center p-1.5 text-foreground hover:bg-muted',
200
+ )}
201
+ aria-label={props.label ?? (props.triggerLabel ? undefined : 'Open menu')}
202
+ >
203
+ {/* Slotted trigger wins; otherwise build one from the trigger* props;
204
+ otherwise fall back to a "more" glyph. */}
205
+ <slot name="trigger">
206
+ <Show when={props.triggerIcon}>{renderIcon(props.triggerIcon, { class: 'size-4 shrink-0' })}</Show>
207
+ <Show when={props.triggerLabel}>{props.triggerLabel}</Show>
208
+ <Show when={props.triggerIconTrailing}>{renderIcon(props.triggerIconTrailing, { class: 'size-3.5 shrink-0 opacity-60' })}</Show>
209
+ <Show when={!props.triggerIcon && !props.triggerLabel}><MoreHorizontal class="size-4" /></Show>
210
+ </slot>
211
+ </DropdownTrigger>
212
+ <DropdownContent class="min-w-[15rem]">
213
+ {renderItems((props.items as KaiMenuItem[] | undefined) ?? [])}
214
+ </DropdownContent>
215
+ </Dropdown>
216
+ );
217
+ });
@@ -1,5 +1,6 @@
1
1
  import { Show, createSignal, onMount, onCleanup } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
+ import { readSlots, MESSAGE_SLOTS } from './slots';
3
4
  import { ChatConfig, useChatConfig, type ProseSize } from '../primitives/chat-config';
4
5
  import { Message, MessageAvatar, MessageBody } from '../components/message';
5
6
  import { createMessageFeedback } from '../primitives/message-feedback';
@@ -27,6 +28,11 @@ interface Props extends Record<string, unknown> {
27
28
  avatarSrc?: string;
28
29
  /** Convenience avatar fallback text (used when `message.avatar` is not set). */
29
30
  avatarFallback?: string;
31
+ /** Avatar rail mode. `'none'` omits the avatar rail entirely so the body spans
32
+ * the full row (predictable layout when you never show avatars). Any other
33
+ * value keeps the default behaviour: the built-in avatar when one resolves, or
34
+ * your `slot="avatar"` content when projected (which REPLACES the built-in). */
35
+ avatar?: 'none' | string;
30
36
  }
31
37
 
32
38
  /** Events fired by `<kai-message>`. */
@@ -54,7 +60,8 @@ defineWebComponent<Props, Events>('kai-message', {
54
60
  actionsReveal: 'always',
55
61
  avatarSrc: undefined,
56
62
  avatarFallback: undefined,
57
- }, (props, { dispatch, flag, element }) => {
63
+ avatar: undefined,
64
+ }, (props, { dispatch, flag, element, expose }) => {
58
65
  const outer = useChatConfig();
59
66
  const msg = (): ChatMessage =>
60
67
  props.message ?? { id: 'message', role: props.role ?? 'assistant', content: props.content ?? '' };
@@ -62,12 +69,27 @@ defineWebComponent<Props, Events>('kai-message', {
62
69
  // re-render when the host swaps in a fresh `message` object during streaming.
63
70
  const feedback = createMessageFeedback({
64
71
  emit: (detail) => dispatch('kai-message-action', detail),
65
- target: () => element,
72
+ // No `target`: a STANDALONE <kai-message> must not anchor its copy/feedback
73
+ // toast to the individual message (that lands mid-thread in a compose-your-own
74
+ // list). Let them route to the global region (top of the viewport), which is
75
+ // where a confirmation belongs across a hand-built thread. (Inside <kai-chat>
76
+ // the chat owns feedback and targets ITSELF, so in-chat toasts still stay in-chat.)
77
+ });
78
+
79
+ // Imperative method API — `copy()` runs the exact path of the built-in copy
80
+ // action (`feedback.handleAction(msg, 'copy')`): writes the content to the
81
+ // clipboard, shows the transient copied-check on the bar, and emits
82
+ // `kai-message-action{action:'copy'}`.
83
+ expose({
84
+ /** Copy the message content to the clipboard and show the copied check. */
85
+ copy: () => feedback.handleAction(msg(), 'copy'),
66
86
  });
67
87
 
68
88
  // Read declarative <kai-action> children from light DOM.
69
89
  // Shadow DOM with no <slot> suppresses them visually — they're invisible data carriers.
70
90
  const [slottedActions, setSlottedActions] = createSignal<import('../elements/chat-types').CustomAction[]>([]);
91
+ // Which composition slots (before-body / after-body / avatar) the consumer filled.
92
+ const [slots, setSlots] = createSignal<Record<string, boolean>>({});
71
93
  onMount(() => {
72
94
  const read = () => {
73
95
  const nodes = [...element.querySelectorAll('kai-action')];
@@ -77,6 +99,7 @@ defineWebComponent<Props, Events>('kai-message', {
77
99
  icon: n.getAttribute('icon') ?? undefined,
78
100
  tooltip: n.getAttribute('tooltip') ?? undefined,
79
101
  })));
102
+ setSlots(readSlots(element, MESSAGE_SLOTS));
80
103
  };
81
104
  read();
82
105
  const observer = new MutationObserver(read);
@@ -89,6 +112,12 @@ defineWebComponent<Props, Events>('kai-message', {
89
112
  (props.avatarSrc || props.avatarFallback
90
113
  ? { src: props.avatarSrc as string | undefined, fallback: props.avatarFallback as string | undefined }
91
114
  : undefined);
115
+ // Avatar rail state. `avatar="none"` omits the rail; a filled `slot="avatar"`
116
+ // REPLACES the built-in; otherwise the built-in renders when one resolves.
117
+ const noAvatar = () => props.avatar === 'none';
118
+ const hasAvatarSlot = () => !!slots()['avatar'];
119
+ // The rail shows when not suppressed and there's either a slot or a resolved avatar.
120
+ const showRail = () => !noAvatar() && (hasAvatarSlot() || !!avatar());
92
121
  const reveal = () => (props.actionsReveal === 'hover' ? 'hover' : 'always');
93
122
  // markdown: explicit prop/attribute wins; otherwise default by role.
94
123
  const markdownExplicit = () =>
@@ -109,12 +138,32 @@ defineWebComponent<Props, Events>('kai-message', {
109
138
  activeFeedback={feedback.resolveFeedback(msg())}
110
139
  copied={feedback.isCopied(msg().id)}
111
140
  onAction={(action) => feedback.handleAction(msg(), action)}
141
+ beforeBody={slots()['before-body'] ? <slot name="before-body" /> : undefined}
142
+ afterBody={slots()['after-body'] ? <slot name="after-body" /> : undefined}
112
143
  />
113
144
  );
114
145
 
115
146
  // Row carries `group` so a hover-revealed action bar fades in on row hover.
116
147
  const rowGroup = () => (reveal() === 'hover' ? 'group ' : '');
117
148
 
149
+ // The avatar rail: a filled `slot="avatar"` REPLACES the built-in MessageAvatar
150
+ // (the consumer owns that node, wrapped in `part="avatar"` so it's still
151
+ // styleable + consistent with the built-in part name).
152
+ const avatarRail = () => (
153
+ <Show
154
+ when={hasAvatarSlot()}
155
+ fallback={
156
+ <Show when={avatar()}>
157
+ {(av) => <MessageAvatar src={av().src ?? ''} alt={av().alt ?? ''} fallback={av().fallback} />}
158
+ </Show>
159
+ }
160
+ >
161
+ <div part="avatar" class="shrink-0">
162
+ <slot name="avatar" />
163
+ </div>
164
+ </Show>
165
+ );
166
+
118
167
  return (
119
168
  <ChatConfig
120
169
  proseSize={props.proseSize}
@@ -123,21 +172,19 @@ defineWebComponent<Props, Events>('kai-message', {
123
172
  portalMount={outer.portalMount()}
124
173
  >
125
174
  <Show
126
- when={avatar()}
175
+ when={showRail()}
127
176
  fallback={
128
177
  <Message class={`${rowGroup()}${isUser() ? 'flex-col items-end' : 'flex-col items-start'}`}>
129
178
  {body()}
130
179
  </Message>
131
180
  }
132
181
  >
133
- {(av) => (
134
- <Message class={rowGroup()}>
135
- <MessageAvatar src={av().src ?? ''} alt={av().alt ?? ''} fallback={av().fallback} />
136
- <div class={`flex min-w-0 flex-1 flex-col ${isUser() ? 'items-end' : 'items-start'}`}>
137
- {body()}
138
- </div>
139
- </Message>
140
- )}
182
+ <Message class={rowGroup()}>
183
+ {avatarRail()}
184
+ <div class={`flex min-w-0 flex-1 flex-col ${isUser() ? 'items-end' : 'items-start'}`}>
185
+ {body()}
186
+ </div>
187
+ </Message>
141
188
  </Show>
142
189
  </ChatConfig>
143
190
  );
@@ -1,6 +1,8 @@
1
1
  import { createSignal, onCleanup, onMount } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
3
  import { ModelSwitcher } from '../components/model-switcher';
4
+ import { wireDisclosure } from './disclosure';
5
+ import type { DropdownController } from '../ui/dropdown';
4
6
  import type { ModelOption } from '../types';
5
7
 
6
8
  interface Props extends Record<string, unknown> {
@@ -8,12 +10,22 @@ interface Props extends Record<string, unknown> {
8
10
  models: ModelOption[];
9
11
  /** The currently-selected model id. Defaults to the first model. */
10
12
  currentModel?: string;
13
+ /** Drive/observe the dropdown's open state (Shoelace-style: settable + reflected
14
+ * to the `open` attribute, the dropdown still self-manages on click/keyboard).
15
+ * Set `el.open = true`, or `<kai-model-switcher open>`; listen for `kai-open-change`. */
16
+ open?: boolean;
17
+ /** Initial open state on mount (uncontrolled seed). */
18
+ defaultOpen?: boolean;
19
+ /** Disable the trigger — click/keyboard and `show()` no longer open the dropdown. */
20
+ disabled?: boolean;
11
21
  }
12
22
 
13
23
  /** Events fired by `<kai-model-switcher>`. */
14
24
  interface Events {
15
25
  /** A model was selected. */
16
26
  'kai-model-change': { modelId: string };
27
+ /** The model dropdown opened or closed (by click, keyboard, Escape, outside-click, or a method). */
28
+ 'kai-open-change': { open: boolean };
17
29
  }
18
30
 
19
31
  /**
@@ -65,7 +77,18 @@ export function parseKaiModelElement(n: Element): ModelOption {
65
77
  defineWebComponent<Props, Events>('kai-model-switcher', {
66
78
  models: [],
67
79
  currentModel: undefined,
68
- }, (props, { dispatch, element }) => {
80
+ open: undefined,
81
+ defaultOpen: undefined,
82
+ disabled: undefined,
83
+ }, (props, ctx) => {
84
+ const { dispatch, element, flag } = ctx;
85
+ let api: DropdownController | undefined;
86
+
87
+ // The standard overlay surface: settable+reflecting `open`, kai-open-change,
88
+ // show/hide/toggle, disabled-gating. See ./disclosure. When <=1 model the inner
89
+ // Dropdown never mounts, so `api` stays undefined and these methods no-op.
90
+ wireDisclosure(ctx, () => api, () => props.open);
91
+
69
92
  // Read declarative <kai-model> children from light DOM.
70
93
  // Shadow DOM with no <slot> suppresses them visually — they're invisible data carriers.
71
94
  const [slottedModels, setSlottedModels] = createSignal<ModelOption[]>([]);
@@ -88,6 +111,9 @@ defineWebComponent<Props, Events>('kai-model-switcher', {
88
111
  models={allModels()}
89
112
  currentModelId={props.currentModel ?? allModels()[0]?.id ?? ''}
90
113
  onModelChange={(modelId) => dispatch('kai-model-change', { modelId })}
114
+ defaultOpen={flag('defaultOpen')}
115
+ disabled={flag('disabled')}
116
+ controllerRef={(a) => (api = a)}
91
117
  />
92
118
  );
93
119
  });
@@ -0,0 +1,87 @@
1
+ import { createSignal } from 'solid-js';
2
+ import { defineWebComponent } from './define';
3
+ import { Nav, type KaiNavItem } from '../ui/nav';
4
+
5
+ interface Props extends Record<string, unknown> {
6
+ /** The nav items. Set as a JS property (array, not an attribute). Each item may
7
+ * carry `children` (a collapsible group), a `status` dot, and trailing `meta`
8
+ * text. */
9
+ items?: KaiNavItem[];
10
+ /** Active item id (controlled). */
11
+ value?: string;
12
+ /** Initial active id when uncontrolled. */
13
+ defaultValue?: string;
14
+ /** Ids of group items collapsed on first render (groups default to expanded).
15
+ * Set as a JS property (array). */
16
+ defaultCollapsed?: string[];
17
+ }
18
+
19
+ interface Events {
20
+ /** A nav item was activated. */
21
+ 'kai-nav-select': { id: string };
22
+ /** A row's trailing `action` button was activated (not a select). `value` is
23
+ * the item id; `action` echoes the item's `{ icon, label }`. */
24
+ 'kai-nav-item-action': { value: string; action?: { icon: string; label: string } };
25
+ /** A `closable` row's trailing close button was activated (not a select).
26
+ * `value` is the item id. */
27
+ 'kai-nav-item-close': { value: string };
28
+ }
29
+
30
+ /**
31
+ * `<kai-nav>` — a vertical navigation list driven by a JSON `items` tree
32
+ * (id + label + optional leading `icon`, a trailing text `badge`, a trailing
33
+ * icon). Items may nest via `children` (a collapsible group with a disclosure
34
+ * chevron), carry a `status` dot (`{ tone, label?, pulse? }`), and a trailing
35
+ * `meta` string (e.g. a relative time). The active item is `value`; selecting a
36
+ * leaf fires `kai-nav-select` (group rows toggle expand/collapse instead).
37
+ *
38
+ * Items may also carry an `action` (`{ icon, label }`) or `closable: true`, which
39
+ * render a trailing button — firing `kai-nav-item-action` `{ value, action }` or
40
+ * `kai-nav-item-close` `{ value }` (never `kai-nav-select`). Style it via
41
+ * `::part(item-action)`.
42
+ *
43
+ * ```html
44
+ * <kai-nav default-value="home"></kai-nav>
45
+ * <script type="module">
46
+ * const nav = document.querySelector('kai-nav');
47
+ * nav.items = [
48
+ * { id: 'home', label: 'New task', icon: 'plus', trailing: 'pencil' },
49
+ * { id: 'acme', label: 'Acme', icon: 'folder', children: [
50
+ * { id: 't1', label: 'Refactor auth', status: { tone: 'info', label: 'Working', pulse: true }, meta: '2m' },
51
+ * { id: 't2', label: 'Landing page', status: { tone: 'success', label: 'Done' }, meta: '1d' },
52
+ * ] },
53
+ * { id: 'dispatch', label: 'Dispatch', icon: 'share', badge: 'Beta' },
54
+ * ];
55
+ * nav.addEventListener('kai-nav-select', (e) => console.log(e.detail.id));
56
+ * </script>
57
+ * ```
58
+ * Restyle via `::part(nav)` / `::part(item)` (active items carry `aria-current`),
59
+ * plus `::part(group)` / `::part(chevron)` / `::part(status)` / `::part(meta)`.
60
+ */
61
+ defineWebComponent<Props, Events>('kai-nav', {
62
+ items: undefined,
63
+ value: undefined,
64
+ defaultValue: undefined,
65
+ defaultCollapsed: undefined,
66
+ }, (props, { dispatch, expose }) => {
67
+ const [internal, setInternal] = createSignal(props.defaultValue as string | undefined);
68
+ const value = () => (props.value as string | undefined) ?? internal();
69
+ const select = (id: string) => { setInternal(id); dispatch('kai-nav-select', { id }); };
70
+
71
+ expose({
72
+ /** Activate an item by id (fires kai-nav-select). */
73
+ select: (id: string) => select(id),
74
+ });
75
+
76
+ return (
77
+ <Nav
78
+ items={props.items as KaiNavItem[] | undefined}
79
+ value={value()}
80
+ defaultCollapsed={props.defaultCollapsed as string[] | undefined}
81
+ onItemSelect={select}
82
+ onItemAction={(id, action) => dispatch('kai-nav-item-action', { value: id, action })}
83
+ onItemClose={(id) => dispatch('kai-nav-item-close', { value: id })}
84
+ part="nav"
85
+ />
86
+ );
87
+ });
@@ -0,0 +1,53 @@
1
+ import { Notice, noticeIconNode } from '../ui/notice';
2
+ import { defineWebComponent } from './define';
3
+
4
+ interface Props extends Record<string, unknown> {
5
+ /** `neutral` (default) · `info` · `warning` · `error` · `success`. Drives the
6
+ * leading icon's color and the a11y role (`alert` for errors, else `status`). */
7
+ severity?: 'neutral' | 'info' | 'warning' | 'error' | 'success';
8
+ /** Leading icon: omit for the severity default, `"none"` to hide it, or a named
9
+ * icon to override. */
10
+ icon?: string;
11
+ /** Show a dismiss (×) that hides the notice and emits `kai-dismiss`. */
12
+ dismissible?: boolean;
13
+ }
14
+
15
+ /** Events fired by `<kai-notice>`. */
16
+ interface Events {
17
+ /** The notice was dismissed via its × (it also hides itself). */
18
+ 'kai-dismiss': void;
19
+ }
20
+
21
+ /**
22
+ * `<kai-notice>` — a self-contained inline notice / alert. Put the message as
23
+ * light-DOM text and an optional `slot="action"` (e.g. a link); it carries the
24
+ * severity icon, the right a11y role, and an optional self-dismissing ×.
25
+ *
26
+ * It owns the notice box, not its placement — you position it in your own layout
27
+ * (above a composer, at the top of a panel, …).
28
+ *
29
+ * For a custom leading icon, slot any inline SVG via `slot="icon"` (it wins over
30
+ * the severity/`icon` default — the same escape hatch as `kai-button`).
31
+ *
32
+ * ```html
33
+ * <kai-notice severity="warning" dismissible>
34
+ * Claude Fable 5 is currently unavailable.
35
+ * <a slot="action" href="#">Learn more</a>
36
+ * </kai-notice>
37
+ * ```
38
+ */
39
+ defineWebComponent<Props, Events>('kai-notice', {
40
+ severity: 'neutral',
41
+ icon: undefined,
42
+ dismissible: false,
43
+ }, (props, { dispatch, flag }) => (
44
+ <Notice
45
+ severity={props.severity ?? 'neutral'}
46
+ iconSlot={<slot name="icon">{noticeIconNode(props.severity ?? 'neutral', props.icon)}</slot>}
47
+ dismissible={flag('dismissible')}
48
+ onDismiss={() => dispatch('kai-dismiss')}
49
+ action={<slot name="action" />}
50
+ >
51
+ <slot />
52
+ </Notice>
53
+ ));
@@ -0,0 +1,119 @@
1
+ import { createSignal, createEffect, Show } from 'solid-js';
2
+ import { defineWebComponent } from './define';
3
+ import { PaneGroup, type PaneTab } from '../ui/pane-group';
4
+
5
+ interface Props extends Record<string, unknown> {
6
+ /** The tabs to render. An array of `{ id, name, status?, needsAttention?, number? }`
7
+ * set as a JS PROPERTY (not an HTML attribute). */
8
+ tabs?: PaneTab[];
9
+ /** The active tab id (controlled, and reflected to the `active` ATTRIBUTE so
10
+ * `::part`/`[active]` selectors and the per-tab named slot follow it). Set it as
11
+ * the `active` attribute or drive it from `kai-tab-change`; omit for uncontrolled
12
+ * (the first tab). */
13
+ active?: string;
14
+ /** Highlight the frame as the ACTIVE group in a multi-group layout. Attribute:
15
+ * `focused`. */
16
+ focused?: boolean;
17
+ }
18
+
19
+ /** Events fired by `<kai-pane-group>`. All non-bubbling — listen on the element. */
20
+ interface Events {
21
+ /** A tab was selected (click, Enter/Space, or arrow-key move). `detail.id` is
22
+ * the tab's id. */
23
+ 'kai-tab-change': { id: string };
24
+ /** A tab's close (×) was clicked. Drop the tab from `tabs` yourself. */
25
+ 'kai-tab-close': { id: string };
26
+ /** A tab's "…" overflow was clicked. Open your own menu from `detail.id`. */
27
+ 'kai-tab-menu': { id: string };
28
+ }
29
+
30
+ /**
31
+ * `<kai-pane-group>` — an editor group: a TAB STRIP (numbered-status-badge tabs)
32
+ * over the active tab's pane content. The reusable "one column = a group of agents
33
+ * shown as tabs" primitive from the Multi-Agent Workspace. Composable: a `tabs`
34
+ * property + slots + parts + events, not a config blob — the group owns the tab UX,
35
+ * you own the pane content.
36
+ *
37
+ * Each tab leads with a tone-colored NUMBERED BADGE (color = status, digit = the
38
+ * keyboard ⌥-jump number), then the name, the status word (on the active tab / on
39
+ * hover / always for needs-attention), a "…" overflow, and a close "×".
40
+ *
41
+ * Set the `tabs` property in JavaScript (array, not attribute):
42
+ *
43
+ * ```html
44
+ * <kai-pane-group active="atlas">
45
+ * <!-- one named slot per tab id; the group shows the active one -->
46
+ * <div slot="atlas">…Atlas pane…</div>
47
+ * <div slot="otto">…Otto pane…</div>
48
+ * </kai-pane-group>
49
+ * <script type="module">
50
+ * import '@kitn.ai/ui/elements';
51
+ * const group = document.querySelector('kai-pane-group');
52
+ * group.tabs = [
53
+ * { id: 'atlas', name: 'Atlas', status: { tone: 'working', label: 'Running', pulse: true } },
54
+ * { id: 'otto', name: 'Otto', status: { tone: 'blocked', label: 'Needs input' }, needsAttention: true },
55
+ * ];
56
+ * group.addEventListener('kai-tab-change', (e) => console.log(e.detail.id));
57
+ * </script>
58
+ * ```
59
+ *
60
+ * Pane content — TWO composable patterns:
61
+ * - NAMED SLOT PER TAB: give each pane `slot="<tab id>"`; the group projects the
62
+ * active tab's slot and swaps it itself on selection (no consumer JS needed).
63
+ * - DEFAULT SLOT: put one body in the default slot and swap it yourself in
64
+ * response to `kai-tab-change`. Both work; pick whichever fits.
65
+ *
66
+ * Methods: `el.select(id)` selects a tab (fires `kai-tab-change`); `el.focus()`
67
+ * focuses the active tab. Parts: `::part(tabs|tab|body)` (also `::part(menu|close)`).
68
+ */
69
+ defineWebComponent<Props, Events>('kai-pane-group', {
70
+ tabs: undefined,
71
+ active: undefined,
72
+ focused: false,
73
+ }, (props, { element, dispatch, flag, expose }) => {
74
+ const tabs = () => (props.tabs as PaneTab[] | undefined) ?? [];
75
+ // Controlled/uncontrolled: the `active` prop/attribute wins; otherwise the
76
+ // element manages its own, falling back to the first tab. `change` always writes
77
+ // the internal value AND emits `kai-tab-change` so a controlling app can react.
78
+ const [internal, setInternal] = createSignal<string | undefined>(props.active as string | undefined);
79
+ const active = () => (props.active as string | undefined) ?? internal() ?? tabs()[0]?.id;
80
+ const change = (id: string) => {
81
+ setInternal(id);
82
+ dispatch('kai-tab-change', { id });
83
+ };
84
+
85
+ // Reflect the resolved active id to the `active` attribute so `[active="…"]` /
86
+ // `::part` selectors and the consumer's per-tab named slot follow selection.
87
+ // Writing the same value is idempotent, so no feedback loop with the prop.
88
+ createEffect(() => {
89
+ const a = active();
90
+ if (a != null) element.setAttribute('active', a);
91
+ });
92
+
93
+ expose({
94
+ /** Select a tab by id (fires `kai-tab-change`). Ignores unknown ids. */
95
+ select: (id: string) => {
96
+ if (tabs().some((t) => t.id === id)) change(id);
97
+ },
98
+ /** Focus the active tab in the strip. */
99
+ focus: () => {
100
+ element.shadowRoot?.querySelector<HTMLElement>('[part="tab"][tabindex="0"]')?.focus();
101
+ },
102
+ });
103
+
104
+ return (
105
+ <PaneGroup
106
+ tabs={tabs()}
107
+ active={active()}
108
+ focused={flag('focused')}
109
+ onTabChange={change}
110
+ onTabClose={(id) => dispatch('kai-tab-close', { id })}
111
+ onTabMenu={(id) => dispatch('kai-tab-menu', { id })}
112
+ >
113
+ {/* Active tab's content: the per-tab named slot, plus the default slot for the
114
+ swap-it-yourself pattern. A consumer uses one or the other. */}
115
+ <Show when={active()}>{(a) => <slot name={a()} />}</Show>
116
+ <slot />
117
+ </PaneGroup>
118
+ );
119
+ });