@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,202 @@
1
+ import { splitProps, Show, createSignal, createEffect, on, onCleanup } from 'solid-js';
2
+ import { cn } from '../utils/cn';
3
+ import { Button } from '../ui/button';
4
+ import { Tooltip } from '../ui/tooltip';
5
+
6
+ /** Imperative handle exposed via `controllerRef` — surfaces the playback controls
7
+ * so the `<kai-voice-output>` facade can forward them as instance methods. Both
8
+ * the native (speechSynthesis) and model (synthesize → Audio) paths run through
9
+ * these, so manual clicks and programmatic calls behave identically. */
10
+ export interface VoiceOutputController {
11
+ /** Speak the current `text` (native by default, model if `synthesize` is set). */
12
+ speak(): void;
13
+ /** Pause playback (resumable). */
14
+ pause(): void;
15
+ /** Resume paused playback. */
16
+ resume(): void;
17
+ /** Stop playback and reset. */
18
+ stop(): void;
19
+ }
20
+
21
+ export interface VoiceOutputProps {
22
+ /** The utterance to read aloud. */
23
+ text: string;
24
+ /** Speak automatically when `text` is set/changed. */
25
+ autoplay?: boolean;
26
+ /** TTS model seam: given text, return an audio Blob to play. When set, the
27
+ * native speechSynthesis path is bypassed. Mirrors VoiceInput's `onTranscribe`. */
28
+ onSynthesize?: (text: string) => Promise<Blob>;
29
+ /** Fires whenever playback starts or stops. */
30
+ onSpeakingChange?: (speaking: boolean) => void;
31
+ /** Fires once the model path resolves audio (model path only). */
32
+ onSynthesized?: (blob: Blob) => void;
33
+ disabled?: boolean;
34
+ class?: string;
35
+ /** Receive the imperative controller once mounted. The `<kai-voice-output>`
36
+ * facade forwards these as element methods (speak/pause/resume/stop). */
37
+ controllerRef?: (controller: VoiceOutputController) => void;
38
+ }
39
+
40
+ /** True when the browser exposes the Web Speech synthesis API. */
41
+ function hasSpeechSynthesis(): boolean {
42
+ return typeof window !== 'undefined' && 'speechSynthesis' in window;
43
+ }
44
+
45
+ export function VoiceOutput(props: VoiceOutputProps) {
46
+ const [local] = splitProps(props, ['text', 'disabled', 'class']);
47
+ const [isSpeaking, setIsSpeaking] = createSignal(false);
48
+ const [isLoading, setIsLoading] = createSignal(false);
49
+
50
+ // The model path plays through one reused <Audio>; the native path drives
51
+ // speechSynthesis. Only one is live at a time (branch on onSynthesize).
52
+ let audio: HTMLAudioElement | undefined;
53
+ let objectUrl: string | undefined;
54
+ let utterance: SpeechSynthesisUtterance | undefined;
55
+
56
+ // No way to speak at all → render disabled. A model seam OR native synthesis
57
+ // is enough; absent both, the control is inert (see the facade/spec).
58
+ const capable = () => !!props.onSynthesize || hasSpeechSynthesis();
59
+
60
+ const label = () =>
61
+ isLoading() ? 'Synthesizing...' : isSpeaking() ? 'Stop' : 'Read aloud';
62
+
63
+ function revokeUrl() {
64
+ if (objectUrl) {
65
+ URL.revokeObjectURL(objectUrl);
66
+ objectUrl = undefined;
67
+ }
68
+ }
69
+
70
+ // Native path: speechSynthesis.speak(new SpeechSynthesisUtterance(text)).
71
+ function speakNative() {
72
+ if (!hasSpeechSynthesis() || !local.text) return;
73
+ window.speechSynthesis.cancel();
74
+ utterance = new SpeechSynthesisUtterance(local.text);
75
+ utterance.onend = () => setIsSpeaking(false);
76
+ utterance.onerror = () => setIsSpeaking(false);
77
+ setIsSpeaking(true);
78
+ window.speechSynthesis.speak(utterance);
79
+ }
80
+
81
+ // Model path: await onSynthesize(text) → play the Blob via an <Audio>.
82
+ async function speakModel() {
83
+ if (!props.onSynthesize || !local.text) return;
84
+ setIsLoading(true);
85
+ try {
86
+ const blob = await props.onSynthesize(local.text);
87
+ props.onSynthesized?.(blob);
88
+ revokeUrl();
89
+ objectUrl = URL.createObjectURL(blob);
90
+ audio ??= new Audio();
91
+ audio.src = objectUrl;
92
+ audio.onended = () => setIsSpeaking(false);
93
+ audio.onerror = () => setIsSpeaking(false);
94
+ setIsSpeaking(true);
95
+ await audio.play();
96
+ } catch {
97
+ setIsSpeaking(false);
98
+ } finally {
99
+ setIsLoading(false);
100
+ }
101
+ }
102
+
103
+ function speak() {
104
+ if (props.onSynthesize) void speakModel();
105
+ else speakNative();
106
+ }
107
+
108
+ function stop() {
109
+ if (props.onSynthesize) {
110
+ if (audio) {
111
+ audio.pause();
112
+ audio.currentTime = 0;
113
+ }
114
+ } else if (hasSpeechSynthesis()) {
115
+ window.speechSynthesis.cancel();
116
+ }
117
+ setIsSpeaking(false);
118
+ }
119
+
120
+ function pause() {
121
+ if (props.onSynthesize) audio?.pause();
122
+ else if (hasSpeechSynthesis()) window.speechSynthesis.pause();
123
+ }
124
+
125
+ function resume() {
126
+ if (props.onSynthesize) void audio?.play();
127
+ else if (hasSpeechSynthesis()) window.speechSynthesis.resume();
128
+ }
129
+
130
+ function handleClick() {
131
+ if (isSpeaking()) stop();
132
+ else speak();
133
+ }
134
+
135
+ // Emit speaking transitions to the host. `defer: true` skips the spurious
136
+ // initial `false` — only real start/stop transitions fire.
137
+ createEffect(on(isSpeaking, (speaking) => {
138
+ props.onSpeakingChange?.(speaking);
139
+ }, { defer: true }));
140
+
141
+ // Autoplay: speak when text first arrives / changes (defer skips the mount
142
+ // value so an empty seed doesn't speak).
143
+ createEffect(on(() => local.text, (text) => {
144
+ if (props.autoplay && text) speak();
145
+ }, { defer: true }));
146
+
147
+ props.controllerRef?.({ speak, pause, resume, stop });
148
+
149
+ onCleanup(() => {
150
+ stop();
151
+ revokeUrl();
152
+ });
153
+
154
+ // Speaker icon (idle)
155
+ const SpeakerIcon = () => (
156
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
157
+ <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
158
+ <path d="M19.07 4.93a10 10 0 010 14.14M15.54 8.46a5 5 0 010 7.07" />
159
+ </svg>
160
+ );
161
+
162
+ // Square stop icon (speaking)
163
+ const StopIcon = () => (
164
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
165
+ <rect x="4" y="4" width="16" height="16" rx="2" />
166
+ </svg>
167
+ );
168
+
169
+ // Spinner (model synthesis in flight)
170
+ const Spinner = () => (
171
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="animate-spin">
172
+ <path d="M21 12a9 9 0 11-6.219-8.56" />
173
+ </svg>
174
+ );
175
+
176
+ return (
177
+ <div class={cn('relative inline-flex items-center justify-center', local.class)}>
178
+ <Tooltip content={label()}>
179
+ <Button
180
+ part="button"
181
+ variant="ghost"
182
+ size="icon-sm"
183
+ aria-label={label()}
184
+ aria-pressed={isSpeaking()}
185
+ onClick={handleClick}
186
+ disabled={local.disabled || !capable() || isLoading()}
187
+ class={cn('relative z-10 rounded-full transition-all duration-300')}
188
+ >
189
+ <Show when={isLoading()}>
190
+ <Spinner />
191
+ </Show>
192
+ <Show when={!isLoading() && isSpeaking()}>
193
+ <StopIcon />
194
+ </Show>
195
+ <Show when={!isLoading() && !isSpeaking()}>
196
+ <SpeakerIcon />
197
+ </Show>
198
+ </Button>
199
+ </Tooltip>
200
+ </div>
201
+ );
202
+ }
@@ -0,0 +1,67 @@
1
+ import { defineWebComponent } from './define';
2
+ import { AgentCard, type AgentStatus } from '../ui/agent-card';
3
+
4
+ interface Props extends Record<string, unknown> {
5
+ /** The agent's name — the primary label. Attribute: `name`. */
6
+ name?: string;
7
+ /** Selected / focused state: highlighted border + surface. Attribute: `active`. */
8
+ active?: boolean;
9
+ /** Raise a prominent "Needs you" pill plus a glowing amber edge — the
10
+ * attention-routing signal that pulls focus to this agent. Attribute:
11
+ * `needs-attention`. */
12
+ needsAttention?: boolean;
13
+ /** Run status — a JS PROPERTY (object), not an attribute. Shape:
14
+ * `{ tone, label?, pulse? }`, where `tone` is one of `working` | `idle` |
15
+ * `done` | `error` | `blocked` (maps to the kit's tool hues), `label` is an
16
+ * optional short string beside the dot, and `pulse` animates the dot. Set it
17
+ * with `el.status = { tone: 'working', label: 'Working', pulse: true }`. */
18
+ status?: AgentStatus;
19
+ }
20
+
21
+ /** Events fired by `<kai-agent-card>`. */
22
+ interface Events {
23
+ /** The card was activated — clicked, or Enter / Space while focused. Promote
24
+ * this agent back to focus. */
25
+ 'kai-activate': void;
26
+ /** The trailing "..." kebab was clicked. The consumer opens its own menu; the
27
+ * card only surfaces the affordance (the click does not also activate the card). */
28
+ 'kai-menu': void;
29
+ }
30
+
31
+ /**
32
+ * `<kai-agent-card>` — the compact glanceable card for one agent in a multi-agent
33
+ * workspace. The agent name with a leading tone-colored status dot, an optional
34
+ * "Needs you" attention treatment, an `active` (selected) state, and a trailing
35
+ * "..." overflow button.
36
+ *
37
+ * Set `status` as a JS property (it's an object); `name` is a string attribute and
38
+ * `active` / `needs-attention` are boolean attributes. Listen for `kai-activate`
39
+ * (promote to focus) and `kai-menu` (open your own per-agent menu).
40
+ *
41
+ * ```html
42
+ * <kai-agent-card name="Refactor bot" active></kai-agent-card>
43
+ * <script type="module">
44
+ * import '@kitn.ai/ui/elements';
45
+ * const card = document.querySelector('kai-agent-card');
46
+ * card.status = { tone: 'working', label: 'Working', pulse: true };
47
+ * card.addEventListener('kai-activate', () => focusAgent());
48
+ * card.addEventListener('kai-menu', () => openMenu());
49
+ * </script>
50
+ * ```
51
+ * Recolor the status dot via `::part(status)` and the kebab via `::part(menu)`.
52
+ */
53
+ defineWebComponent<Props, Events>('kai-agent-card', {
54
+ name: undefined,
55
+ active: undefined,
56
+ needsAttention: undefined,
57
+ status: undefined,
58
+ }, (props, { dispatch, flag }) => (
59
+ <AgentCard
60
+ name={(props.name as string) ?? ''}
61
+ active={flag('active')}
62
+ needsAttention={flag('needsAttention')}
63
+ status={(props.status as AgentStatus) ?? { tone: 'idle' }}
64
+ onActivate={() => dispatch('kai-activate')}
65
+ onMenu={() => dispatch('kai-menu')}
66
+ />
67
+ ));
@@ -1,14 +1,19 @@
1
1
  import { createSignal, onMount, onCleanup } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
- import { Artifact, type ArtifactFile, type ArtifactTab } from '../components/artifact';
3
+ import { Artifact, type ArtifactController, type ArtifactFile, type ArtifactTab } from '../components/artifact';
4
4
 
5
5
  interface Props extends Record<string, unknown> {
6
6
  /** URL the preview iframe frames. Consumer-controlled. */
7
7
  src?: string;
8
8
  /** Files for the Code tab tree + each file's preview `url`. Set as a JS property (array). */
9
9
  files: ArtifactFile[];
10
- /** Active tab: `preview` (default) or `code`. */
10
+ /** Controlled active tab: `preview` or `code`. When set, the artifact follows it
11
+ * (re-asserted on change). Leave unset for an uncontrolled tab (see `defaultTab`). */
11
12
  tab?: ArtifactTab;
13
+ /** Uncontrolled INITIAL tab (used only when `tab` is unset). Default `preview`.
14
+ * Seeds the starting tab; the user can then switch freely without the consumer
15
+ * re-asserting a controlled `tab`. */
16
+ defaultTab?: ArtifactTab;
12
17
  /** Selected file path — syncs the tree highlight, Code source, and preview. */
13
18
  activeFile?: string;
14
19
  /** iframe `sandbox` override. Secure default `allow-scripts allow-forms` (NOT `allow-same-origin`). */
@@ -35,6 +40,11 @@ interface Props extends Record<string, unknown> {
35
40
  standalone?: boolean;
36
41
  /** Show the address but make it read-only (visible, nav-tracking, non-editable). */
37
42
  readonlyPath?: boolean;
43
+ /** Friendly address shown in the path field instead of the real current url
44
+ * (read-only, non-navigable). Use when the framed url is not consumer-facing
45
+ * (e.g. a `data:` blob) so a clean address shows instead of leaking it. Scalar
46
+ * string: set as the `display-url` attribute or the `displayUrl` property. */
47
+ displayUrl?: string;
38
48
  }
39
49
 
40
50
  interface Events extends Record<string, unknown> {
@@ -59,7 +69,8 @@ interface Events extends Record<string, unknown> {
59
69
  defineWebComponent<Props, Events>('kai-artifact', {
60
70
  src: undefined,
61
71
  files: [],
62
- tab: 'preview',
72
+ tab: undefined,
73
+ defaultTab: undefined,
63
74
  activeFile: undefined,
64
75
  sandbox: 'allow-scripts allow-forms',
65
76
  iframeTitle: undefined,
@@ -73,9 +84,44 @@ defineWebComponent<Props, Events>('kai-artifact', {
73
84
  noTabs: false,
74
85
  standalone: false,
75
86
  readonlyPath: false,
76
- }, (props, { element, dispatch, flag }) => {
87
+ displayUrl: undefined,
88
+ }, (props, { element, dispatch, flag, expose }) => {
77
89
  const [maximized, setMaximized] = createSignal(flag('maximized'));
78
90
 
91
+ // ── Imperative API (instance methods on the host) ──────────────────────────
92
+ // Pattern C: the Artifact component owns the history stack + tab/file/maximize
93
+ // state and hands up a controller; the facade captures it and exposes delegating
94
+ // methods. Every internal handler still fires its event (navigate → kai-navigate;
95
+ // selectFile → kai-file-select; maximize/restore → kai-maximize-change). Names are
96
+ // collision-checked against the props: openExternal (not openInTab — a prop),
97
+ // maximize/restore (not maximized — a prop), navigate/selectFile (not src/activeFile
98
+ // — props); NO tab-switching method (tab is a prop → switch via `el.tab`).
99
+ let controller: ArtifactController | undefined;
100
+ expose({
101
+ /** Go back in the artifact's own history stack (no-op when there's no prior entry). */
102
+ back: () => controller?.back(),
103
+ /** Go forward in the history stack (no-op when there's no forward entry). */
104
+ forward: () => controller?.forward(),
105
+ /** Force-reload the current preview url (also re-renders an inline PDF). */
106
+ reload: () => controller?.reload(),
107
+ /** Navigate to the `src` home url (no-op when there's no `src`). */
108
+ home: () => controller?.home(),
109
+ /** Push + load a url in the preview — the path-field submit path (fires kai-navigate). */
110
+ navigate: (url: string) => controller?.navigate(url),
111
+ /** Select a file by path: highlights the tree, shows its source, navigates the
112
+ * preview (fires kai-file-select + kai-navigate). Named selectFile to avoid the
113
+ * `activeFile` prop. */
114
+ selectFile: (path: string) => controller?.selectFile(path),
115
+ /** Open the current url in a new browser tab (no-op when there's no concrete url).
116
+ * Named openExternal, NOT openInTab — that's a prop (toolbar button visibility). */
117
+ openExternal: () => controller?.openExternal(),
118
+ /** Enter the maximized view-state (fires kai-maximize-change{maximized:true}).
119
+ * Named maximize, NOT maximized — that's a prop. */
120
+ maximize: () => controller?.maximize(),
121
+ /** Exit the maximized view-state (fires kai-maximize-change{maximized:false}). */
122
+ restore: () => controller?.restore(),
123
+ });
124
+
79
125
  const onMaximizeChange = (next: boolean) => {
80
126
  setMaximized(next);
81
127
  // 1) The PROTOCOL intent — raw, bubbling + composed (NOT via dispatch()).
@@ -113,6 +159,7 @@ defineWebComponent<Props, Events>('kai-artifact', {
113
159
  src={props.src}
114
160
  files={props.files}
115
161
  tab={props.tab}
162
+ defaultTab={props.defaultTab}
116
163
  activeFile={props.activeFile}
117
164
  sandbox={props.sandbox}
118
165
  iframeTitle={props.iframeTitle}
@@ -126,10 +173,12 @@ defineWebComponent<Props, Events>('kai-artifact', {
126
173
  showTabs={!flag('noTabs')}
127
174
  standalone={flag('standalone')}
128
175
  readonlyPath={flag('readonlyPath')}
176
+ displayUrl={props.displayUrl}
129
177
  onMaximizeChange={onMaximizeChange}
130
178
  onNavigate={(url) => dispatch('kai-navigate', { url })}
131
179
  onTabChange={(tab) => dispatch('kai-tab-change', { tab })}
132
180
  onFileSelect={(path) => dispatch('kai-file-select', { path })}
181
+ controllerRef={(c) => (controller = c)}
133
182
  />
134
183
  </div>
135
184
  </>
@@ -118,6 +118,7 @@ defineWebComponent<Props, Events>('kai-attachments', {
118
118
  }
119
119
  >
120
120
  <img
121
+ part="preview"
121
122
  src={item.url}
122
123
  alt={getAttachmentLabel(item)}
123
124
  class="block max-h-64 max-w-xs rounded object-contain"
@@ -0,0 +1,33 @@
1
+ import { Avatar } from '../ui/avatar';
2
+ import { defineWebComponent } from './define';
3
+
4
+ interface Props extends Record<string, unknown> {
5
+ /** Image URL/data-URI. When absent, the `fallback` initials show instead. */
6
+ src?: string;
7
+ /** Alt text for the image. Defaults to `fallback`. */
8
+ alt?: string;
9
+ /** Short text shown when there's no image — usually initials (e.g. "JD", "AI"). */
10
+ fallback?: string;
11
+ /** Size token: `sm` | `md` (default) | `lg`. */
12
+ size?: 'sm' | 'md' | 'lg';
13
+ }
14
+
15
+ /**
16
+ * `<kai-avatar>` — a person/entity avatar: a rounded image that falls back to
17
+ * initials when there's no `src`. This is an *identity* badge (the thing next to
18
+ * a message or in a conversation list), not a generic icon — for a glyph, use an
19
+ * `icon` prop on another element.
20
+ *
21
+ * ```html
22
+ * <kai-avatar src="/me.jpg" fallback="JD"></kai-avatar>
23
+ * <kai-avatar fallback="AI" size="sm"></kai-avatar>
24
+ * ```
25
+ */
26
+ defineWebComponent<Props>('kai-avatar', {
27
+ src: undefined,
28
+ alt: undefined,
29
+ fallback: '',
30
+ size: 'md',
31
+ }, (props) => (
32
+ <Avatar src={props.src} alt={props.alt} fallback={props.fallback ?? ''} size={props.size ?? 'md'} />
33
+ ));
@@ -0,0 +1,32 @@
1
+ import { Badge } from '../ui/badge';
2
+ import { defineWebComponent } from './define';
3
+
4
+ interface Props extends Record<string, unknown> {
5
+ /** `default` (muted pill) · `count` (compact number badge) · `citation`
6
+ * (filled primary, for inline citation markers). Defaults to `default`. */
7
+ variant?: 'default' | 'count' | 'citation';
8
+ }
9
+
10
+ /**
11
+ * `<kai-badge>` — a small pill for labels, status, counts, or citation markers.
12
+ * Put the content as light-DOM text.
13
+ *
14
+ * ```html
15
+ * <kai-badge>Beta</kai-badge>
16
+ * <kai-badge variant="count">3</kai-badge>
17
+ * <kai-badge variant="citation">1</kai-badge>
18
+ * ```
19
+ * Restyle via `::part(badge)`.
20
+ */
21
+ defineWebComponent<Props>('kai-badge', {
22
+ variant: 'default',
23
+ }, (props) => (
24
+ <>
25
+ {/* Base sets `:host{display:block}`; a badge/pill flows inline with text and
26
+ beside sibling badges, so inline-flex like kai-button. */}
27
+ <style>{':host{display:inline-flex}'}</style>
28
+ <Badge variant={props.variant ?? 'default'} part="badge">
29
+ <slot />
30
+ </Badge>
31
+ </>
32
+ ));
@@ -0,0 +1,126 @@
1
+ import { Show } from 'solid-js';
2
+ import { Button } from '../ui/button';
3
+ import { renderIcon } from '../ui/icon';
4
+ import { defineWebComponent } from './define';
5
+
6
+ interface Props extends Record<string, unknown> {
7
+ /** Visual style. `default` (filled), `subtle` (muted text, hover tint — the
8
+ * toolbar icon look), `ghost` (transparent, hover fill), `outline`, or
9
+ * `destructive`. Defaults to `default`. */
10
+ variant?: 'default' | 'subtle' | 'ghost' | 'outline' | 'destructive';
11
+ /** Size token. `icon` / `icon-sm` are square (for icon-only buttons); `sm` /
12
+ * `md` / `lg` size text buttons. Defaults to `md`. */
13
+ size?: 'sm' | 'md' | 'lg' | 'icon' | 'icon-sm';
14
+ /** Leading icon: a named icon (e.g. `"mic"`, `"plus"`), an image URL/data-URI,
15
+ * or plain text. Renders before any slotted label. */
16
+ icon?: string;
17
+ /** Trailing icon, after the label (e.g. `"chevron-down"` for a menu affordance). */
18
+ iconTrailing?: string;
19
+ /** Accessible name. REQUIRED for icon-only buttons (no visible text); ignored
20
+ * when you slot visible text, which already names the button. */
21
+ label?: string;
22
+ /** Disable the button (non-interactive, dimmed). */
23
+ disabled?: boolean;
24
+ /** Stretch the button to the full width of its container (a block button) —
25
+ * e.g. a card CTA or a stacked action. Attribute: `full`. */
26
+ full?: boolean;
27
+ /** Justify the button's content: `start`, `center` (default), or `end`.
28
+ * Combine with `full` for a full-width, left-aligned button. */
29
+ align?: 'start' | 'center' | 'end';
30
+ /** Native button `type`. Defaults to `button` (so it never submits a form). */
31
+ type?: 'button' | 'submit' | 'reset';
32
+ }
33
+
34
+ /** Events fired by `<kai-button>`. */
35
+ interface Events {
36
+ /** The button was activated (pointer or keyboard). Carries no detail. The
37
+ * native `click` also bubbles (composed) for consumers who prefer it. */
38
+ 'kai-click': void;
39
+ }
40
+
41
+ /**
42
+ * `<kai-button>` — the kit's button as a drop-in element, so consumers compose
43
+ * polished, theme-aware controls instead of hand-rolling `<button>` + inline
44
+ * hover styles. Put the label as light-DOM text; use `icon` for a leading glyph
45
+ * and `label` to name an icon-only button.
46
+ *
47
+ * ```html
48
+ * <kai-button variant="subtle" size="icon" icon="mic" label="Voice input"></kai-button>
49
+ * <kai-button variant="ghost" icon-trailing="chevron-down">High</kai-button>
50
+ * <kai-button>Send</kai-button>
51
+ * <kai-button label="Ship"><svg slot="icon" viewBox="0 0 24 24">…</svg></kai-button>
52
+ * ```
53
+ *
54
+ * The `icon` prop renders a curated/URL icon; for anything else, slot your own
55
+ * inline SVG via `slot="icon"` (it wins over `icon`). Restyle via `::part(button)`.
56
+ * Emits `kai-click`.
57
+ */
58
+ defineWebComponent<Props, Events>('kai-button', {
59
+ variant: 'default',
60
+ size: 'md',
61
+ icon: undefined,
62
+ iconTrailing: undefined,
63
+ label: undefined,
64
+ disabled: false,
65
+ full: false,
66
+ align: 'center',
67
+ type: 'button',
68
+ }, (props, { dispatch, flag, element, expose }) => {
69
+ // `icon` / `icon-sm` are square, icon-ONLY sizes: suppress the text label and
70
+ // trailing icon so a stray label doesn't get cramped into the square (the
71
+ // `label` prop still names it for assistive tech).
72
+ const iconOnly = () => props.size === 'icon' || props.size === 'icon-sm';
73
+
74
+ // ── Imperative API (instance methods on the host) ──────────────────────────
75
+ // The real <button> lives in the shadow root, so native focus()/blur()/click()
76
+ // on the host hit the wrapper, not the control. Forward to the inner button.
77
+ // These shadow the inherited HTMLElement methods — intended; expose() uses
78
+ // defineProperty so the override sticks. No collision with the props above.
79
+ expose({
80
+ /** Focus the inner `<button>` (host.focus() would focus the wrapper). */
81
+ focus: (options?: FocusOptions) =>
82
+ element.shadowRoot?.querySelector('button')?.focus(options),
83
+ /** Blur the inner `<button>`. */
84
+ blur: () => element.shadowRoot?.querySelector('button')?.blur(),
85
+ /** Programmatically activate the button — runs the same path as a user
86
+ * click and fires kai-click. Forwarding to the inner button means
87
+ * `disabled` is respected automatically. */
88
+ click: () => element.shadowRoot?.querySelector('button')?.click(),
89
+ });
90
+ return (
91
+ <>
92
+ {/* The host shrinks to the label by default (inline-flex), so a text button
93
+ is only as wide as its content — until a parent stretches it. A text
94
+ button's inner control is w-full, so when the host IS stretched (a flex
95
+ column with items-stretch, e.g. a card's collapsed footer, or an explicit
96
+ `full`) the button fills it. `full` forces that standalone (a block CTA).
97
+ Icon buttons stay square (no w-full). */}
98
+ <style>{':host{display:inline-flex}:host([full]){display:block}'}</style>
99
+ <Button
100
+ part="button"
101
+ variant={props.variant ?? 'default'}
102
+ size={props.size ?? 'md'}
103
+ align={props.align ?? 'center'}
104
+ full={flag('full') || !iconOnly()}
105
+ type={props.type ?? 'button'}
106
+ disabled={flag('disabled')}
107
+ aria-label={props.label}
108
+ onClick={() => dispatch('kai-click')}
109
+ >
110
+ {/* Leading icon: a slotted SVG (slot="icon") wins — drop in any icon
111
+ library or your own; otherwise the `icon` prop renders a curated/URL one. */}
112
+ <slot name="icon">
113
+ <Show when={props.icon}>
114
+ {renderIcon(props.icon, { class: 'size-4 shrink-0', imgClass: 'size-4 shrink-0', spanClass: 'inline-flex size-4 shrink-0 items-center justify-center', ariaHidden: true })}
115
+ </Show>
116
+ </slot>
117
+ <Show when={!iconOnly()}>
118
+ <slot />
119
+ </Show>
120
+ <Show when={props.iconTrailing && !iconOnly()}>
121
+ {renderIcon(props.iconTrailing, { class: 'size-4 shrink-0 opacity-60', imgClass: 'size-4 shrink-0', spanClass: 'inline-flex size-4 shrink-0 items-center justify-center', ariaHidden: true })}
122
+ </Show>
123
+ </Button>
124
+ </>
125
+ );
126
+ });
Binary file