@kitn.ai/ui 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (493) hide show
  1. package/README.md +55 -17
  2. package/dist/components/artifact.d.ts +39 -1
  3. package/dist/components/attachment-types.d.ts +12 -0
  4. package/dist/components/attachments.d.ts +2 -10
  5. package/dist/components/card.d.ts +27 -0
  6. package/dist/components/chain-of-thought.d.ts +78 -2
  7. package/dist/components/chat-scope-picker.d.ts +7 -0
  8. package/dist/components/chat-thread.d.ts +39 -16
  9. package/dist/components/choice-card.d.ts +27 -0
  10. package/dist/components/coachmark.d.ts +49 -0
  11. package/dist/components/composer-dom.d.ts +35 -0
  12. package/dist/components/composer-highlight.d.ts +48 -0
  13. package/dist/components/composer-history.d.ts +34 -0
  14. package/dist/components/composer.d.ts +86 -0
  15. package/dist/components/confirm-card.d.ts +17 -0
  16. package/dist/components/conversation-item.d.ts +9 -0
  17. package/dist/components/conversation-list.d.ts +36 -1
  18. package/dist/components/dismissed-stub.d.ts +22 -0
  19. package/dist/components/file-tree.d.ts +15 -0
  20. package/dist/components/form.d.ts +34 -0
  21. package/dist/components/markdown.d.ts +3 -0
  22. package/dist/components/message.d.ts +71 -2
  23. package/dist/components/model-switcher.d.ts +7 -0
  24. package/dist/components/prompt-input.d.ts +13 -4
  25. package/dist/components/prompt-suggestion.d.ts +9 -1
  26. package/dist/components/reasoning.d.ts +14 -1
  27. package/dist/components/response-compare-types.d.ts +66 -0
  28. package/dist/components/response-compare.d.ts +65 -0
  29. package/dist/components/screen.d.ts +46 -0
  30. package/dist/components/tasks-card.d.ts +50 -1
  31. package/dist/components/toast.d.ts +58 -0
  32. package/dist/components/tool-types.d.ts +10 -0
  33. package/dist/components/tool.d.ts +8 -8
  34. package/dist/components/use-card-resolution.d.ts +10 -6
  35. package/dist/components/voice-input.d.ts +27 -0
  36. package/dist/components/voice-output.d.ts +33 -0
  37. package/dist/core-C8fzo39E.js +12 -0
  38. package/dist/custom-elements.json +8472 -1691
  39. package/dist/elements/agent-card.d.ts +1 -0
  40. package/dist/elements/agent-card.js +1 -0
  41. package/dist/elements/artifact.js +1 -0
  42. package/dist/elements/attachments.js +1 -0
  43. package/dist/elements/autoloader.d.ts +2 -0
  44. package/dist/elements/autoloader.js +1 -0
  45. package/dist/elements/avatar.d.ts +1 -0
  46. package/dist/elements/avatar.js +1 -0
  47. package/dist/elements/badge.d.ts +1 -0
  48. package/dist/elements/badge.js +1 -0
  49. package/dist/elements/button.d.ts +1 -0
  50. package/dist/elements/button.js +1 -0
  51. package/dist/elements/card.js +1 -0
  52. package/dist/elements/cards.d.ts +1 -0
  53. package/dist/elements/cards.js +1 -0
  54. package/dist/elements/chain-of-thought.d.ts +0 -12
  55. package/dist/elements/chain-of-thought.js +1 -0
  56. package/dist/elements/chat-scope-picker.js +1 -0
  57. package/dist/elements/chat-types.d.ts +8 -2
  58. package/dist/elements/chat-workspace.js +1 -0
  59. package/dist/elements/chat.js +1 -0
  60. package/dist/elements/checkpoint.js +1 -0
  61. package/dist/elements/choice.js +1 -0
  62. package/dist/elements/chunks/Icon-DLLBeLG5.js +1 -0
  63. package/dist/elements/chunks/action-icons-UB4V5FNq.js +1 -0
  64. package/dist/elements/chunks/arrow-left-C-gwlUmx.js +1 -0
  65. package/dist/elements/chunks/attachments-CgbErf1r.js +1 -0
  66. package/dist/elements/chunks/badge-DTQpgB6N.js +1 -0
  67. package/dist/elements/chunks/bash-InADTalH.js +1 -0
  68. package/dist/elements/chunks/button-XDUM6lXs.js +1 -0
  69. package/dist/elements/chunks/card-CBlFZ-7I.js +1 -0
  70. package/dist/elements/chunks/card-routing-C986KuUA.js +1 -0
  71. package/dist/elements/chunks/chat-thread-BIhmqwNL.js +1 -0
  72. package/dist/elements/chunks/check-hGUoVIKb.js +1 -0
  73. package/dist/elements/chunks/chevron-down-DDoaSUtO.js +1 -0
  74. package/dist/elements/chunks/chevron-right-CdGEUakB.js +1 -0
  75. package/dist/elements/chunks/circle-BKAZdmzb.js +1 -0
  76. package/dist/elements/chunks/circle-check-CmYG-y3I.js +1 -0
  77. package/dist/elements/chunks/circle-x-DewgAEym.js +1 -0
  78. package/dist/elements/chunks/cn-CU7UAWzk.js +1 -0
  79. package/dist/elements/chunks/code-block-DedwxwFI.js +1 -0
  80. package/dist/elements/chunks/collapsible-FfgmTHtM.js +1 -0
  81. package/dist/elements/chunks/composer-Cfbw5HKT.js +65 -0
  82. package/dist/elements/chunks/context-DwJmxlRE.js +1 -0
  83. package/dist/elements/chunks/conversation-list-DsCQMfPq.js +1 -0
  84. package/dist/elements/chunks/core-AYMC6_lb.js +12 -0
  85. package/dist/elements/chunks/css-M7EaDHN_.js +1 -0
  86. package/dist/elements/chunks/default-input-BuqsoENC.js +1 -0
  87. package/dist/elements/chunks/define-rGsaWsLL.js +1 -0
  88. package/dist/elements/chunks/disclosure-CwoAkpMH.js +1 -0
  89. package/dist/elements/chunks/download-DJ06G3Bz.js +1 -0
  90. package/dist/elements/chunks/dropdown-BFg8ri_R.js +1 -0
  91. package/dist/elements/chunks/ellipsis-dlN6YvGw.js +1 -0
  92. package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +141 -0
  93. package/dist/elements/chunks/external-link-DBX2lc_R.js +1 -0
  94. package/dist/elements/chunks/file-text-HfwUx4F9.js +1 -0
  95. package/dist/elements/chunks/file-tree-C6Toj71u.js +1 -0
  96. package/dist/elements/chunks/folder-MYuqa9Xp.js +1 -0
  97. package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +1 -0
  98. package/dist/elements/chunks/github-light-JYsPkUQd.js +1 -0
  99. package/dist/elements/chunks/hover-card-gE7iyXdW.js +1 -0
  100. package/dist/elements/chunks/html-CPZ3oZQ7.js +1 -0
  101. package/dist/elements/chunks/icon-Vqz4ivrY.js +1 -0
  102. package/dist/elements/chunks/index-BCRhi84a.js +1 -0
  103. package/dist/elements/chunks/info-B_toFS0l.js +1 -0
  104. package/dist/elements/chunks/input-gzbHYZvQ.js +1 -0
  105. package/dist/elements/chunks/javascript-C25yR2R2.js +1 -0
  106. package/dist/elements/chunks/json-DxJze_jm.js +1 -0
  107. package/dist/elements/chunks/kbd-n49c4KZm.js +1 -0
  108. package/dist/elements/chunks/link-CKPs9yM0.js +1 -0
  109. package/dist/elements/chunks/loader-q6MamGus.js +1 -0
  110. package/dist/elements/chunks/markdown-DBrcqq4S.js +64 -0
  111. package/dist/elements/chunks/message-CTqaYI0s.js +1 -0
  112. package/dist/elements/chunks/message-feedback-Cvzm03w0.js +1 -0
  113. package/dist/elements/chunks/message-square-CUg9eRCi.js +1 -0
  114. package/dist/elements/chunks/minimize-2-l2klxP6K.js +1 -0
  115. package/dist/elements/chunks/model-switcher-CmyjiHO1.js +1 -0
  116. package/dist/elements/chunks/overlay-C8sOYqjT.js +1 -0
  117. package/dist/elements/chunks/paperclip-42Ia7xHD.js +1 -0
  118. package/dist/elements/chunks/progress-bar-tzKMWAwO.js +1 -0
  119. package/dist/elements/chunks/prompt-suggestion-D3F6vP_A.js +1 -0
  120. package/dist/elements/chunks/reasoning-BJNmmyov.js +1 -0
  121. package/dist/elements/chunks/resizable-BRsk19qI.js +1 -0
  122. package/dist/elements/chunks/rotate-cw-BgcggLHC.js +1 -0
  123. package/dist/elements/chunks/scroll-area-CgGbFFbT.js +1 -0
  124. package/dist/elements/chunks/separator-8hM4GdHE.js +1 -0
  125. package/dist/elements/chunks/settings-CaUIYOg-.js +1 -0
  126. package/dist/elements/chunks/settings-group-CYjOVIZQ.js +1 -0
  127. package/dist/elements/chunks/share-BTYM3Ddt.js +1 -0
  128. package/dist/elements/chunks/skeleton-DsTYrPUe.js +1 -0
  129. package/dist/elements/chunks/slots-DkZ-Cmha.js +1 -0
  130. package/dist/elements/chunks/star-9R3LBQ9n.js +1 -0
  131. package/dist/elements/chunks/store-CYl5Y0_u.js +1 -0
  132. package/dist/elements/chunks/svelte--5p79yCD.js +1 -0
  133. package/dist/elements/chunks/text-shimmer-CaYGv8Se.js +1 -0
  134. package/dist/elements/chunks/textarea-NEr2SLcD.js +1 -0
  135. package/dist/elements/chunks/thumbs-up-DZYZkFfc.js +1 -0
  136. package/dist/elements/chunks/toast-store-ClxVZRcc.js +1 -0
  137. package/dist/elements/chunks/tool-CHZOmoe9.js +1 -0
  138. package/dist/elements/chunks/tooltip-WpHElELC.js +1 -0
  139. package/dist/elements/chunks/triangle-alert-BlS80PUg.js +1 -0
  140. package/dist/elements/chunks/tsx-B8rCNbgL.js +1 -0
  141. package/dist/elements/chunks/typescript-RycA9KXf.js +1 -0
  142. package/dist/elements/chunks/use-card-resolution-VSVoxDeJ.js +1 -0
  143. package/dist/elements/chunks/video-DxTPZqT8.js +1 -0
  144. package/dist/elements/chunks/vue-BmIZj4XD.js +1 -0
  145. package/dist/elements/chunks/x-C1qtndxn.js +1 -0
  146. package/dist/elements/coachmark.d.ts +1 -0
  147. package/dist/elements/coachmark.js +1 -0
  148. package/dist/elements/code-block.js +1 -0
  149. package/dist/elements/command.d.ts +1 -0
  150. package/dist/elements/command.js +1 -0
  151. package/dist/elements/compare.d.ts +1 -0
  152. package/dist/elements/compare.js +1 -0
  153. package/dist/elements/composer.d.ts +1 -0
  154. package/dist/elements/composer.js +1 -0
  155. package/dist/elements/confirm-card.js +1 -0
  156. package/dist/elements/context-meter.js +1 -0
  157. package/dist/elements/conversation-list.d.ts +1 -11
  158. package/dist/elements/conversation-list.js +1 -0
  159. package/dist/elements/default-input.d.ts +20 -9
  160. package/dist/elements/define.d.ts +11 -0
  161. package/dist/elements/dialog.d.ts +1 -0
  162. package/dist/elements/dialog.js +1 -0
  163. package/dist/elements/disclosure.d.ts +37 -0
  164. package/dist/elements/editable-label.d.ts +1 -0
  165. package/dist/elements/editable-label.js +1 -0
  166. package/dist/elements/embed.js +1 -0
  167. package/dist/elements/empty.js +1 -0
  168. package/dist/elements/feedback-bar.js +1 -0
  169. package/dist/elements/file-tree.js +1 -0
  170. package/dist/elements/file-upload.js +1 -0
  171. package/dist/elements/form.js +1 -0
  172. package/dist/elements/hover-card.d.ts +1 -0
  173. package/dist/elements/hover-card.js +1 -0
  174. package/dist/elements/icon.d.ts +1 -0
  175. package/dist/elements/icon.js +1 -0
  176. package/dist/elements/image.js +1 -0
  177. package/dist/elements/input.d.ts +1 -0
  178. package/dist/elements/input.js +1 -0
  179. package/dist/elements/kbd.d.ts +1 -0
  180. package/dist/elements/kbd.js +1 -0
  181. package/dist/elements/link-preview.js +1 -0
  182. package/dist/elements/loader.js +1 -0
  183. package/dist/elements/markdown.js +1 -0
  184. package/dist/elements/menu.d.ts +1 -0
  185. package/dist/elements/menu.js +1 -0
  186. package/dist/elements/message-skills.d.ts +0 -16
  187. package/dist/elements/message-skills.js +1 -0
  188. package/dist/elements/message.js +1 -0
  189. package/dist/elements/model-switcher.d.ts +1 -11
  190. package/dist/elements/model-switcher.js +1 -0
  191. package/dist/elements/nav.d.ts +1 -0
  192. package/dist/elements/nav.js +1 -0
  193. package/dist/elements/notice.d.ts +1 -0
  194. package/dist/elements/notice.js +1 -0
  195. package/dist/elements/pane-group.d.ts +1 -0
  196. package/dist/elements/pane-group.js +1 -0
  197. package/dist/elements/pane.d.ts +1 -0
  198. package/dist/elements/pane.js +1 -0
  199. package/dist/elements/popover.js +1 -0
  200. package/dist/elements/progress-bar.d.ts +1 -0
  201. package/dist/elements/progress-bar.js +1 -0
  202. package/dist/elements/prompt-dock.d.ts +1 -0
  203. package/dist/elements/prompt-dock.js +1 -0
  204. package/dist/elements/prompt-input.d.ts +1 -9
  205. package/dist/elements/prompt-input.js +1 -0
  206. package/dist/elements/prompt-suggestions.d.ts +0 -6
  207. package/dist/elements/prompt-suggestions.js +1 -0
  208. package/dist/elements/reasoning.js +1 -0
  209. package/dist/elements/register.d.ts +10 -0
  210. package/dist/elements/remote.js +1 -0
  211. package/dist/elements/resizable.d.ts +1 -17
  212. package/dist/elements/resizable.js +1 -0
  213. package/dist/elements/response-stream.js +14 -0
  214. package/dist/elements/screen.d.ts +1 -0
  215. package/dist/elements/screen.js +1 -0
  216. package/dist/elements/scroll-area.d.ts +1 -0
  217. package/dist/elements/scroll-area.js +1 -0
  218. package/dist/elements/scroll-button.js +1 -0
  219. package/dist/elements/search.d.ts +1 -0
  220. package/dist/elements/search.js +1 -0
  221. package/dist/elements/segmented.d.ts +1 -0
  222. package/dist/elements/segmented.js +1 -0
  223. package/dist/elements/separator.d.ts +1 -0
  224. package/dist/elements/separator.js +1 -0
  225. package/dist/elements/setting-item.d.ts +1 -0
  226. package/dist/elements/setting-item.js +1 -0
  227. package/dist/elements/settings-group.d.ts +1 -0
  228. package/dist/elements/settings-group.js +1 -0
  229. package/dist/elements/skeleton.d.ts +1 -0
  230. package/dist/elements/skeleton.js +1 -0
  231. package/dist/elements/slots.d.ts +176 -0
  232. package/dist/elements/source.d.ts +0 -17
  233. package/dist/elements/source.js +1 -0
  234. package/dist/elements/status.d.ts +1 -0
  235. package/dist/elements/status.js +1 -0
  236. package/dist/elements/switch.js +1 -0
  237. package/dist/elements/tabs.d.ts +1 -0
  238. package/dist/elements/tabs.js +1 -0
  239. package/dist/elements/tasks.js +1 -0
  240. package/dist/elements/text-shimmer.js +1 -0
  241. package/dist/elements/thinking-bar.js +1 -0
  242. package/dist/elements/toast.d.ts +1 -0
  243. package/dist/elements/toast.js +1 -0
  244. package/dist/elements/tool.js +1 -0
  245. package/dist/elements/tooltip.d.ts +1 -0
  246. package/dist/elements/tooltip.js +1 -0
  247. package/dist/elements/voice-input.js +1 -0
  248. package/dist/elements/voice-output.d.ts +1 -0
  249. package/dist/elements/voice-output.js +1 -0
  250. package/dist/elements.d.ts +772 -61
  251. package/dist/engine-javascript-C1x7zo1_.js +141 -0
  252. package/dist/index.d.ts +15 -2
  253. package/dist/index.js +14405 -9810
  254. package/dist/kai.es.js +1 -0
  255. package/dist/llms/llms-full.txt +1234 -107
  256. package/dist/llms/llms.txt +4 -4
  257. package/dist/mcp.es.js +217 -6
  258. package/dist/primitives/card-contract.d.ts +20 -4
  259. package/dist/primitives/card-recovery.d.ts +55 -0
  260. package/dist/primitives/composer-model.d.ts +22 -0
  261. package/dist/primitives/composer-triggers.d.ts +19 -0
  262. package/dist/primitives/create-kai-chat.d.ts +38 -0
  263. package/dist/primitives/message-feedback.d.ts +35 -0
  264. package/dist/primitives/toast-store.d.ts +118 -0
  265. package/dist/primitives/use-speech-recognition.d.ts +26 -0
  266. package/dist/react/index.d.ts +1166 -98
  267. package/dist/react/runtime.d.ts +9 -2
  268. package/dist/react/use-kai-chat.d.ts +41 -0
  269. package/dist/react.js +575 -186
  270. package/dist/register-impl-CYWGkgbI.js +141 -0
  271. package/dist/schemas/choice.schema.json +5 -0
  272. package/dist/schemas/tasks.schema.json +7 -2
  273. package/dist/state/index.d.ts +4 -0
  274. package/dist/state/messages.d.ts +11 -0
  275. package/dist/state/stream.d.ts +22 -0
  276. package/dist/state/suggestions.d.ts +4 -0
  277. package/dist/state.js +117 -0
  278. package/dist/theme.tokens.css +87 -0
  279. package/dist/types.d.ts +4 -0
  280. package/dist/ui/agent-card.d.ts +61 -0
  281. package/dist/ui/button.d.ts +5 -2
  282. package/dist/ui/card.d.ts +61 -0
  283. package/dist/ui/collapsible.d.ts +15 -1
  284. package/dist/ui/command.d.ts +33 -0
  285. package/dist/ui/dialog.d.ts +42 -0
  286. package/dist/ui/dropdown.d.ts +95 -1
  287. package/dist/ui/editable-label.d.ts +26 -0
  288. package/dist/ui/hover-card.d.ts +13 -1
  289. package/dist/ui/icon.d.ts +18 -0
  290. package/dist/ui/input.d.ts +33 -0
  291. package/dist/ui/kbd.d.ts +21 -0
  292. package/dist/ui/nav.d.ts +62 -0
  293. package/dist/ui/notice.d.ts +31 -0
  294. package/dist/ui/overlay.d.ts +12 -0
  295. package/dist/ui/pane-grid.d.ts +58 -0
  296. package/dist/ui/pane-group.d.ts +75 -0
  297. package/dist/ui/pane.d.ts +78 -0
  298. package/dist/ui/popover.d.ts +11 -1
  299. package/dist/ui/progress-bar.d.ts +23 -0
  300. package/dist/ui/prompt-dock.d.ts +96 -0
  301. package/dist/ui/resizable.d.ts +12 -0
  302. package/dist/ui/scroll-area.d.ts +4 -0
  303. package/dist/ui/segmented.d.ts +28 -0
  304. package/dist/ui/settings-group.d.ts +32 -0
  305. package/dist/ui/skeleton.d.ts +12 -0
  306. package/dist/ui/stat.d.ts +16 -0
  307. package/dist/ui/status.d.ts +13 -0
  308. package/dist/ui/switch.d.ts +8 -1
  309. package/dist/ui/tabs.d.ts +35 -0
  310. package/dist/ui/tooltip.d.ts +20 -1
  311. package/frameworks/react/index.tsx +1100 -163
  312. package/frameworks/react/runtime.tsx +30 -1
  313. package/frameworks/react/use-kai-chat.tsx +87 -0
  314. package/llms-full.txt +1234 -107
  315. package/llms.txt +4 -4
  316. package/package.json +36 -12
  317. package/src/agent-tooling/mcp/manifest.ts +14 -0
  318. package/src/agent-tooling/mcp/tools/debug.ts +194 -6
  319. package/src/agent-tooling/mcp/tools/reference.ts +32 -0
  320. package/src/agent-tooling/mcp/tools/scaffold.ts +162 -1
  321. package/src/components/artifact.tsx +98 -13
  322. package/src/components/attachment-types.ts +13 -0
  323. package/src/components/attachments.tsx +4 -14
  324. package/src/components/card.tsx +109 -15
  325. package/src/components/chain-of-thought.tsx +210 -1
  326. package/src/components/chat-scope-picker.tsx +13 -3
  327. package/src/components/chat-thread.tsx +238 -137
  328. package/src/components/choice-card.tsx +136 -15
  329. package/src/components/coachmark.tsx +245 -0
  330. package/src/components/component-meta.json +921 -108
  331. package/src/components/composer-dom.ts +159 -0
  332. package/src/components/composer-highlight.ts +242 -0
  333. package/src/components/composer-history.ts +82 -0
  334. package/src/components/composer.tsx +979 -0
  335. package/src/components/confirm-card.tsx +69 -2
  336. package/src/components/conversation-item.tsx +69 -7
  337. package/src/components/conversation-list.tsx +134 -37
  338. package/src/components/dismissed-stub.tsx +80 -0
  339. package/src/components/file-tree.tsx +197 -47
  340. package/src/components/form-widgets.tsx +9 -7
  341. package/src/components/form.tsx +161 -20
  342. package/src/components/image.tsx +3 -5
  343. package/src/components/link-preview.tsx +5 -4
  344. package/src/components/markdown.tsx +5 -2
  345. package/src/components/message.tsx +174 -14
  346. package/src/components/model-switcher.tsx +19 -4
  347. package/src/components/prompt-input.tsx +46 -75
  348. package/src/components/prompt-suggestion.tsx +48 -16
  349. package/src/components/reasoning.tsx +29 -6
  350. package/src/components/response-compare-types.ts +127 -0
  351. package/src/components/response-compare.tsx +460 -0
  352. package/src/components/screen.tsx +176 -0
  353. package/src/components/tasks-card.tsx +374 -23
  354. package/src/components/toast.tsx +486 -0
  355. package/src/components/tool-types.ts +10 -0
  356. package/src/components/tool.tsx +22 -16
  357. package/src/components/use-card-resolution.ts +24 -8
  358. package/src/components/voice-input.tsx +102 -19
  359. package/src/components/voice-output.tsx +202 -0
  360. package/src/elements/agent-card.tsx +67 -0
  361. package/src/elements/artifact.tsx +53 -4
  362. package/src/elements/attachments.tsx +1 -0
  363. package/src/elements/autoloader.ts +89 -0
  364. package/src/elements/avatar.tsx +33 -0
  365. package/src/elements/badge.tsx +32 -0
  366. package/src/elements/button.tsx +126 -0
  367. package/src/elements/card-media.jpg +0 -0
  368. package/src/elements/card.tsx +124 -31
  369. package/src/elements/cards.tsx +81 -7
  370. package/src/elements/chain-of-thought.tsx +77 -32
  371. package/src/elements/chat-scope-picker.tsx +35 -8
  372. package/src/elements/chat-types.ts +9 -2
  373. package/src/elements/chat-workspace.tsx +157 -43
  374. package/src/elements/chat.tsx +49 -25
  375. package/src/elements/choice.tsx +71 -19
  376. package/src/elements/coachmark.tsx +90 -0
  377. package/src/elements/command.tsx +209 -0
  378. package/src/elements/compare.tsx +110 -0
  379. package/src/elements/compiled.css +1 -1
  380. package/src/elements/composer.tsx +151 -0
  381. package/src/elements/confirm-card.tsx +36 -11
  382. package/src/elements/conversation-list.tsx +80 -11
  383. package/src/elements/default-input.tsx +75 -53
  384. package/src/elements/define.tsx +47 -6
  385. package/src/elements/dialog.tsx +98 -0
  386. package/src/elements/disclosure.ts +73 -0
  387. package/src/elements/editable-label.tsx +125 -0
  388. package/src/elements/element-manifest.json +310 -0
  389. package/src/elements/element-meta.json +5954 -1605
  390. package/src/elements/element-types.d.ts +771 -60
  391. package/src/elements/file-tree.tsx +12 -2
  392. package/src/elements/file-upload.tsx +1 -1
  393. package/src/elements/form.tsx +54 -11
  394. package/src/elements/hover-card.tsx +80 -0
  395. package/src/elements/icon-names.json +48 -0
  396. package/src/elements/icon.tsx +41 -0
  397. package/src/elements/input.tsx +203 -0
  398. package/src/elements/kbd.tsx +45 -0
  399. package/src/elements/menu.tsx +217 -0
  400. package/src/elements/message.tsx +84 -55
  401. package/src/elements/model-switcher.tsx +27 -1
  402. package/src/elements/nav.tsx +87 -0
  403. package/src/elements/notice.tsx +53 -0
  404. package/src/elements/pane-group.tsx +119 -0
  405. package/src/elements/pane.tsx +129 -0
  406. package/src/elements/popover.tsx +39 -17
  407. package/src/elements/progress-bar.tsx +39 -0
  408. package/src/elements/prompt-dock.tsx +81 -0
  409. package/src/elements/prompt-input.tsx +112 -63
  410. package/src/elements/prompt-suggestions.tsx +25 -9
  411. package/src/elements/reasoning.tsx +30 -9
  412. package/src/elements/register-impl.ts +41 -3
  413. package/src/elements/register.ts +20 -3
  414. package/src/elements/remote.tsx +4 -0
  415. package/src/elements/resizable.tsx +48 -11
  416. package/src/elements/screen.tsx +90 -0
  417. package/src/elements/scroll-area.tsx +33 -0
  418. package/src/elements/search.tsx +180 -0
  419. package/src/elements/segmented.tsx +135 -0
  420. package/src/elements/separator.tsx +36 -0
  421. package/src/elements/setting-item.tsx +50 -0
  422. package/src/elements/settings-group.tsx +37 -0
  423. package/src/elements/skeleton.tsx +45 -0
  424. package/src/elements/slots.ts +607 -0
  425. package/src/elements/source.tsx +13 -6
  426. package/src/elements/status.tsx +42 -0
  427. package/src/elements/styles.css +19 -0
  428. package/src/elements/switch.tsx +89 -14
  429. package/src/elements/tabs.tsx +95 -0
  430. package/src/elements/tasks.tsx +70 -14
  431. package/src/elements/toast.tsx +89 -0
  432. package/src/elements/tool.tsx +43 -9
  433. package/src/elements/tooltip.tsx +85 -0
  434. package/src/elements/video-poster.jpg +0 -0
  435. package/src/elements/voice-input.tsx +66 -16
  436. package/src/elements/voice-output.tsx +69 -0
  437. package/src/index.ts +35 -2
  438. package/src/primitives/card-contract.ts +14 -5
  439. package/src/primitives/card-recovery.ts +149 -0
  440. package/src/primitives/card-routing.ts +3 -0
  441. package/src/primitives/card-schemas/choice.schema.json +5 -0
  442. package/src/primitives/card-schemas/tasks.schema.json +7 -2
  443. package/src/primitives/composer-model.ts +49 -0
  444. package/src/primitives/composer-triggers.ts +35 -0
  445. package/src/primitives/create-kai-chat.ts +66 -0
  446. package/src/primitives/message-feedback.ts +123 -0
  447. package/src/primitives/toast-store.ts +276 -0
  448. package/src/primitives/use-speech-recognition.ts +135 -0
  449. package/src/state/index.ts +6 -0
  450. package/src/state/messages.ts +36 -0
  451. package/src/state/stream.ts +92 -0
  452. package/src/state/suggestions.ts +9 -0
  453. package/src/types.ts +4 -0
  454. package/src/ui/agent-card.tsx +212 -0
  455. package/src/ui/button.tsx +16 -5
  456. package/src/ui/card.tsx +245 -0
  457. package/src/ui/collapsible.tsx +30 -4
  458. package/src/ui/command.tsx +99 -0
  459. package/src/ui/dialog.tsx +217 -0
  460. package/src/ui/dropdown.tsx +375 -13
  461. package/src/ui/editable-label.tsx +112 -0
  462. package/src/ui/hover-card.tsx +28 -5
  463. package/src/ui/icon.tsx +110 -0
  464. package/src/ui/input.tsx +132 -0
  465. package/src/ui/kbd.tsx +118 -0
  466. package/src/ui/nav.tsx +282 -0
  467. package/src/ui/notice.tsx +84 -0
  468. package/src/ui/overlay.tsx +108 -2
  469. package/src/ui/pane-grid.tsx +116 -0
  470. package/src/ui/pane-group.tsx +280 -0
  471. package/src/ui/pane.tsx +193 -0
  472. package/src/ui/popover.tsx +16 -2
  473. package/src/ui/progress-bar.tsx +83 -0
  474. package/src/ui/prompt-dock.tsx +145 -0
  475. package/src/ui/resizable.tsx +69 -1
  476. package/src/ui/scroll-area.tsx +14 -3
  477. package/src/ui/segmented.tsx +109 -0
  478. package/src/ui/settings-group.tsx +67 -0
  479. package/src/ui/skeleton.tsx +62 -5
  480. package/src/ui/stat.tsx +41 -0
  481. package/src/ui/status.tsx +48 -0
  482. package/src/ui/switch.tsx +49 -23
  483. package/src/ui/tabs.tsx +168 -0
  484. package/src/ui/tooltip.tsx +57 -7
  485. package/theme.css +113 -0
  486. package/dist/components/slash-command.d.ts +0 -15
  487. package/dist/kitn-chat.es.js +0 -1
  488. package/dist/register-impl-wCsFPoh9.js +0 -77
  489. package/dist/register-ujhr1nBS.js +0 -1
  490. package/src/components/slash-command.tsx +0 -232
  491. package/src/elements/framework-usage.json +0 -563
  492. /package/dist/{kitn-chat-provider.d.ts → kai-provider.d.ts} +0 -0
  493. /package/dist/{kitn-chat-provider.es.js → kai-provider.es.js} +0 -0
@@ -0,0 +1,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
@@ -1,40 +1,133 @@
1
+ import { createSignal, onCleanup, onMount } from 'solid-js';
1
2
  import { defineWebComponent } from './define';
2
- import { Card } from '../components/card';
3
+ import { Card, type CardAppearance, type CardOrientation } from '../ui/card';
3
4
 
4
5
  interface Props extends Record<string, unknown> {
5
- /** Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. */
6
- heading?: string;
7
- /** Supporting text under the heading. Attribute: `description`. */
8
- description?: string;
9
- /** When set, the card renders its inline error state instead of the body.
10
- * Attribute: `error-message`. */
11
- errorMessage?: string;
12
- /** Compact spacing for dense lists. Attribute: `dense`. */
6
+ /** Surface treatment: `outlined` (default) | `filled` | `plain` | `accent`.
7
+ * Attribute: `appearance`. */
8
+ appearance?: CardAppearance;
9
+ /** `vertical` (default, media on top) | `horizontal` (media at the start) |
10
+ * `responsive` (horizontal when the card's container is wide enough, else
11
+ * vertical — a container query on the card's own width). Attribute: `orientation`. */
12
+ orientation?: CardOrientation;
13
+ /** The card width below which a `responsive` card collapses to vertical and the
14
+ * footer actions stack. A CSS length; default `28rem`. Attribute: `collapse`. */
15
+ collapse?: string;
16
+ /** Tighter spacing for dense lists. Attribute: `dense`. */
13
17
  dense?: boolean;
18
+ /** Show a close (×) that hides the card and emits `kai-dismiss`. Attribute:
19
+ * `dismissible`. Off by default. */
20
+ dismissible?: boolean;
21
+ /** Render the whole card as a link. Attribute: `href`. Wins over `clickable`. */
22
+ href?: string;
23
+ /** `target` for the `href` anchor. Attribute: `target`. */
24
+ target?: string;
25
+ /** `rel` for the `href` anchor. Attribute: `rel`. */
26
+ rel?: string;
27
+ /** Make the whole card a button (`role="button"`, Enter/Space, hover affordance)
28
+ * that emits `kai-card-click`. Attribute: `clickable`. Ignored when `href` is set. */
29
+ clickable?: boolean;
14
30
  }
15
31
 
32
+ /** Events fired by `<kai-card>`. */
33
+ interface Events {
34
+ /** The card was dismissed via its × (it also hides itself). */
35
+ 'kai-dismiss': void;
36
+ /** A `clickable`/`href` card was activated (click, or Enter/Space). */
37
+ 'kai-card-click': void;
38
+ }
39
+
40
+ /** The named slots whose occupancy gates a card region. An empty `<slot>` is
41
+ * always a truthy node, so the facade tracks which are actually filled and only
42
+ * passes those regions to the primitive. */
43
+ const SLOT_NAMES = ['media', 'header', 'header-actions', 'footer', 'footer-actions'] as const;
44
+ type SlotName = (typeof SLOT_NAMES)[number];
45
+
16
46
  /**
17
- * `<kai-card>` — the shared, presentational card chrome every native card composes
18
- * from: an optional media region (`slot="media"`), a heading + description, a body
19
- * (default slot), an actions footer (`slot="actions"`), and one consistent inline
20
- * **error** state (`error-message`). It emits **no** events and reads no context
21
- * it is chrome only; the cards that compose it (e.g. `<kai-form>`) own the contract
22
- * interaction. Isolated in Shadow DOM; theme-aware via the shared kit tokens.
47
+ * `<kai-card>` — the kit's presentational card, modeled on the WebAwesome card:
48
+ * ONE element whose flexibility comes from a few structural slots, `appearance`
49
+ * and `orientation` variants, themeable `::part`s, and a single
50
+ * `--kai-card-spacing` knob. The title/description are not slots they are body
51
+ * (default slot) or `slot="header"` content you mark up yourself.
52
+ *
53
+ * Slots: `media` (full-bleed image/video/illustration), `header` + `header-actions`,
54
+ * the default slot (body), `footer` + `footer-actions`.
55
+ *
56
+ * Behaviors (all OFF by default): `dismissible` (× → `kai-dismiss`), and
57
+ * `href`/`clickable` (whole card a link/button → `kai-card-click`). A
58
+ * clickable/href card must NOT also contain action buttons.
59
+ *
60
+ * ```html
61
+ * <kai-card appearance="filled" dismissible>
62
+ * <div slot="media"><img src="…" alt="…" /></div>
63
+ * <h3 slot="header">2× usage</h3>
64
+ * Do more with a higher session limit.
65
+ * <kai-button slot="footer-actions">Start task</kai-button>
66
+ * </kai-card>
67
+ * ```
23
68
  */
24
- defineWebComponent<Props>('kai-card', {
25
- heading: undefined,
26
- description: undefined,
27
- errorMessage: undefined,
69
+ defineWebComponent<Props, Events>('kai-card', {
70
+ appearance: 'outlined',
71
+ orientation: 'vertical',
72
+ collapse: '28rem',
28
73
  dense: false,
29
- }, (props, { flag }) => (
30
- <Card
31
- heading={props.heading}
32
- description={props.description}
33
- errorMessage={props.errorMessage}
34
- dense={flag('dense')}
35
- media={<slot name="media" />}
36
- actions={<slot name="actions" />}
37
- >
38
- <slot />
39
- </Card>
40
- ));
74
+ dismissible: false,
75
+ href: undefined,
76
+ target: undefined,
77
+ rel: undefined,
78
+ clickable: false,
79
+ }, (props, { element, dispatch, flag }) => {
80
+ // Track which named slots are filled, plus whether the default slot (body) has
81
+ // any content. Re-read on child mutations so streamed/late content lights up
82
+ // its region. An unfilled region is never rendered (no stray padding/divider).
83
+ const [filled, setFilled] = createSignal<Record<SlotName, boolean>>({
84
+ 'media': false, 'header': false, 'header-actions': false, 'footer': false, 'footer-actions': false,
85
+ });
86
+ const [hasBody, setHasBody] = createSignal(false);
87
+
88
+ onMount(() => {
89
+ const read = () => {
90
+ const next = {} as Record<SlotName, boolean>;
91
+ for (const name of SLOT_NAMES) next[name] = !!element.querySelector(`:scope > [slot="${name}"]`);
92
+ setFilled(next);
93
+ // Body = any direct child without a slot attribute (element, or non-blank text).
94
+ setHasBody(
95
+ Array.from(element.childNodes).some(
96
+ (n) =>
97
+ (n.nodeType === Node.ELEMENT_NODE && !(n as Element).hasAttribute('slot')) ||
98
+ (n.nodeType === Node.TEXT_NODE && (n.textContent ?? '').trim() !== ''),
99
+ ),
100
+ );
101
+ };
102
+ read();
103
+ const observer = new MutationObserver(read);
104
+ observer.observe(element, { childList: true, characterData: true, subtree: true });
105
+ onCleanup(() => observer.disconnect());
106
+ });
107
+
108
+ const region = (name: SlotName) => (filled()[name] ? <slot name={name} /> : undefined);
109
+
110
+ return (
111
+ <Card
112
+ appearance={props.appearance as CardAppearance}
113
+ orientation={props.orientation as CardOrientation}
114
+ collapse={props.collapse as string}
115
+ dense={flag('dense')}
116
+ dismissible={flag('dismissible')}
117
+ href={props.href}
118
+ target={props.target}
119
+ rel={props.rel}
120
+ clickable={flag('clickable')}
121
+ onDismiss={() => dispatch('kai-dismiss')}
122
+ onCardClick={() => dispatch('kai-card-click')}
123
+ media={region('media')}
124
+ header={region('header')}
125
+ headerActions={region('header-actions')}
126
+ footer={region('footer')}
127
+ footerActions={region('footer-actions')}
128
+ hasBody={hasBody()}
129
+ >
130
+ <slot />
131
+ </Card>
132
+ );
133
+ });
@@ -4,10 +4,10 @@
4
4
  // `kai-card` events through an optional `policy`. The raw events keep bubbling past
5
5
  // <kai-cards> (composed) so document-level listeners still work. Unknown types render
6
6
  // the Solid CardFallback inline and emit a contract `error`.
7
- import { For, Show, createEffect, onCleanup, onMount, type JSX } from 'solid-js';
7
+ import { For, Show, createEffect, createSignal, on, onCleanup, onMount, type JSX } from 'solid-js';
8
8
  import { Dynamic } from 'solid-js/web';
9
9
  import { defineWebComponent } from './define';
10
- import type { CardEnvelope, CardEvent, CardPolicy } from '../primitives/card-contract';
10
+ import type { CardEnvelope, CardEvent, CardPolicy, CardResolution } from '../primitives/card-contract';
11
11
  import { CARD_EVENT_NAME, emitCardEvent, routeCardEvent } from '../primitives/card-routing';
12
12
  import { mergeCardTags } from '../primitives/card-registry';
13
13
  import { CardFallback } from '../components/card-fallback';
@@ -30,6 +30,33 @@ interface Props extends Record<string, unknown> {
30
30
  policy?: CardPolicy;
31
31
  }
32
32
 
33
+ /** Events fired by `<kai-cards>`. */
34
+ interface Events {
35
+ /** A child card transitioned to a resolved/deferred state (an action was chosen,
36
+ * a form/tasks submission landed, or it was dismissed) — re-emitted off the host
37
+ * as a non-bubbling convenience event so a consumer can observe resolution
38
+ * centrally without diffing the cards array. `detail` = `{ cardId, resolution }`.
39
+ * (A `reopen` un-resolves a card and has no `CardResolution`, so it does NOT fire
40
+ * this — observe reopen via the underlying bubbling `kai-card` event.) */
41
+ 'kai-card-resolved': { cardId: string; resolution: CardResolution };
42
+ }
43
+
44
+ /** Map a terminal/deferred child CardEvent to the CardResolution it produces. Returns
45
+ * `undefined` for events that don't resolve a card (ready/error/etc.) and for
46
+ * `reopen` (which clears resolution → no CardResolution to convey). */
47
+ function resolutionFromEvent(e: CardEvent): CardResolution | undefined {
48
+ switch (e.kind) {
49
+ case 'action':
50
+ return { kind: 'action', action: e.action, payload: e.payload };
51
+ case 'submit':
52
+ return { kind: 'submit', data: e.data };
53
+ case 'dismiss':
54
+ return { kind: 'dismissed' };
55
+ default:
56
+ return undefined;
57
+ }
58
+ }
59
+
33
60
  /** A single resolved child: a known kai-* tag (props set imperatively) or the fallback. */
34
61
  function CardSlot(props: { envelope: CardEnvelope; tag?: string; theme: string; emit: (e: CardEvent) => void }): JSX.Element {
35
62
  let ref: HTMLElement | undefined;
@@ -41,6 +68,9 @@ function CardSlot(props: { envelope: CardEnvelope; tag?: string; theme: string;
41
68
  if (props.envelope.title != null) (ref as unknown as { heading: string }).heading = props.envelope.title;
42
69
  (ref as unknown as { resolution: unknown }).resolution = props.envelope.resolution;
43
70
  ref.setAttribute('theme', props.theme);
71
+ // Stable, queryable id so the host's getCard()/resolve() can find this child
72
+ // node without relying on the (private, scalar-only) cardId property reflecting.
73
+ ref.setAttribute('data-card-id', props.envelope.id);
44
74
  });
45
75
  // Hoist the unknown-type error emit to onMount to avoid side-effect-in-JSX lint issue
46
76
  // and to ensure exactly one error fires.
@@ -59,20 +89,64 @@ function CardSlot(props: { envelope: CardEnvelope; tag?: string; theme: string;
59
89
  );
60
90
  }
61
91
 
62
- defineWebComponent<Props>(
92
+ defineWebComponent<Props, Events>(
63
93
  'kai-cards',
64
94
  { cards: undefined, types: undefined, policy: undefined },
65
- (props, { element }) => {
95
+ (props, { element, dispatch, expose }) => {
96
+ // Local working copy of the card list. The `cards` PROP still drives rendering
97
+ // (a new prop array re-seeds this), but holding a settable copy lets the
98
+ // imperative resolve()/dismiss() methods flip one envelope's resolution and
99
+ // re-render the matching child — the imperative twin of a consumer cloning +
100
+ // reassigning the whole cards array. `on(..., { defer: true })` re-seeds only on
101
+ // a genuine prop change (mount uses the createSignal seed below), preserving any
102
+ // pending imperative resolution until the consumer supplies a new prop array.
103
+ const [cards, setCards] = createSignal<CardEnvelope[]>(props.cards ?? []);
104
+ createEffect(on(() => props.cards, (next) => setCards(next ?? []), { defer: true }));
105
+
66
106
  // Route children's bubbling kai-card events through the policy. Attached to the host
67
107
  // element so composed events from each child's shadow root are caught as they bubble.
68
108
  // The handler reads `props.policy` at EVENT time (not mount time) so setting
69
109
  // `el.policy` after the element is in the DOM — the standard host pattern — works.
70
110
  onMount(() => {
71
- const handler = (e: Event) =>
72
- routeCardEvent(props.policy ?? {}, (e as CustomEvent<CardEvent>).detail);
111
+ const handler = (e: Event) => {
112
+ const detail = (e as CustomEvent<CardEvent>).detail;
113
+ routeCardEvent(props.policy ?? {}, detail);
114
+ // Additionally re-emit the non-bubbling convenience event when a child
115
+ // transitions to a resolved/deferred state — alongside (not instead of) the
116
+ // existing policy routing + the raw bubbling kai-card event.
117
+ const resolution = resolutionFromEvent(detail);
118
+ if (resolution) dispatch('kai-card-resolved', { cardId: detail.cardId, resolution });
119
+ };
73
120
  element.addEventListener(CARD_EVENT_NAME, handler as EventListener);
74
121
  onCleanup(() => element.removeEventListener(CARD_EVENT_NAME, handler as EventListener));
75
122
  });
123
+
124
+ // ── Imperative API (instance methods on the host) ──────────────────────────
125
+ // Pattern B: the methods operate on the facade's own working copy + the rendered
126
+ // child DOM nodes. Resolving an envelope sets its `resolution`, which flows down
127
+ // through CardSlot's effect (sets the child's `resolution` prop) so the child
128
+ // re-renders into its chromed read-only view.
129
+ const resolveCard = (cardId: string, resolution: CardResolution) =>
130
+ setCards((list) =>
131
+ list.some((env) => env.id === cardId)
132
+ ? list.map((env) => (env.id === cardId ? { ...env, resolution } : env))
133
+ : list,
134
+ );
135
+ expose({
136
+ /** Programmatically resolve a child card by id: set that envelope's
137
+ * `resolution` so the child re-renders into its read-only/resolved view — the
138
+ * imperative twin of the consumer mutating the cards array. No-op for an
139
+ * unknown id. */
140
+ resolve: (cardId: string, resolution: CardResolution) => resolveCard(cardId, resolution),
141
+ /** Collapse a card to its re-openable stub from the host side — convenience for
142
+ * `resolve(cardId, { kind: 'dismissed' })`. */
143
+ dismiss: (cardId: string) => resolveCard(cardId, { kind: 'dismissed' }),
144
+ /** Return the live child element node for a card id (or null) so consumers can
145
+ * call that card's own methods (focus/expand/…) without a shadow-DOM query. */
146
+ getCard: (cardId: string): HTMLElement | null =>
147
+ element.shadowRoot?.querySelector<HTMLElement>(`[data-card-id="${CSS.escape(cardId)}"]`) ?? null,
148
+ });
149
+
76
150
  // Read the facade's REACTIVE `theme` prop, not element.getAttribute (which is
77
151
  // not a tracked dependency) — otherwise a theme change on <kai-cards> after the
78
152
  // children first render never propagates, leaving each child card stuck on its
@@ -81,7 +155,7 @@ defineWebComponent<Props>(
81
155
  const tags = () => mergeCardTags(props.types);
82
156
  return (
83
157
  <div class="flex flex-col gap-3">
84
- <For each={props.cards ?? []}>
158
+ <For each={cards()}>
85
159
  {(env) => (
86
160
  <CardSlot
87
161
  envelope={env}
@@ -1,49 +1,74 @@
1
- import { For, Show, createSignal, onMount, onCleanup } from 'solid-js';
1
+ import { createSignal, onMount, onCleanup } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
3
  import {
4
- ChainOfThought,
5
- ChainOfThoughtStep,
6
- ChainOfThoughtTrigger,
7
- ChainOfThoughtContent,
8
- ChainOfThoughtItem,
4
+ ChainOfThoughtAccordion,
5
+ type ChainOfThoughtController,
6
+ type ChainOfThoughtStepData,
7
+ type ChainOfThoughtType,
9
8
  } from '../components/chain-of-thought';
10
9
 
11
- interface Step {
12
- /** The step's heading (the always-visible trigger). */
13
- label: string;
14
- /** Optional expandable detail. */
15
- content?: string;
16
- }
10
+ /**
11
+ * A reasoning step descriptor.
12
+ *
13
+ * `id` is an OPTIONAL stable key. The Accordion's open-set keys (used by `value`,
14
+ * `defaultValue`, the `kai-value-change` payload, and the index→key resolution
15
+ * behind the methods) are `step.id` when present, else `String(index)`. Set `id`
16
+ * if you want to drive/observe a step by a meaningful key rather than position.
17
+ */
18
+ type Step = ChainOfThoughtStepData;
17
19
 
18
20
  interface Props extends Record<string, unknown> {
19
21
  /** The reasoning steps. Set as a JS property. Compound sub-parts collapse to
20
- * this one data model (Route 1). */
22
+ * this one data model (Route 1). Each `{ label, content?, id? }`. */
21
23
  steps: Step[];
24
+ /** Open mode: `'multiple'` (default — any number of steps open at once) or
25
+ * `'single'` (at most one open; opening a step closes the others). */
26
+ type?: ChainOfThoughtType;
27
+ /** Controlled open step key(s). When set, it WINS over user interaction (the
28
+ * consumer owns the open set). String in `single` mode, string[] in
29
+ * `multiple` mode. Set as a JS property. */
30
+ value?: string | string[];
31
+ /** Uncontrolled INITIAL open step key(s) — seeds which steps render expanded.
32
+ * Ignored once `value` is provided. Set as a JS property. */
33
+ defaultValue?: string | string[];
34
+ }
35
+
36
+ /** Events fired by `<kai-chain-of-thought>`. */
37
+ interface Events {
38
+ /** The open set changed — by user click OR an expand()/collapse()/toggle()
39
+ * call. `value` is a string in `single` mode, a string[] in `multiple` mode.
40
+ * (Maps Radix Accordion's onValueChange.) */
41
+ 'kai-value-change': { value: string | string[] };
22
42
  }
23
43
 
24
44
  /** Parse a single light-DOM `<kai-step>` element into a `Step` descriptor.
25
45
  * Attribute mapping:
26
46
  * - `label` → Step.label (the always-visible heading)
47
+ * - `step-id` → Step.id (optional stable open-set key)
27
48
  * - textContent → Step.content (optional expandable detail)
28
49
  */
29
50
  export function parseKaiStepElement(n: Element): Step {
30
51
  return {
31
52
  label: n.getAttribute('label') ?? '',
32
53
  content: n.textContent?.trim() || undefined,
54
+ id: n.getAttribute('step-id') ?? undefined,
33
55
  };
34
56
  }
35
57
 
36
58
  /**
37
59
  * `<kai-chain-of-thought>` — step-by-step reasoning with connectors and
38
- * per-step collapsible detail.
60
+ * per-step collapsible detail. An Accordion: by default every step is
61
+ * independently collapsible (`type="multiple"`, all closed); set
62
+ * `type="single"` for one-open-at-a-time.
39
63
  *
40
64
  * **Route 1 — JS property:** set the `steps` property to an array of
41
- * `{ label, content? }` objects.
65
+ * `{ label, content?, id? }` objects.
42
66
  *
43
67
  * **Route 2 — declarative children:** compose `<kai-step>` child elements in
44
68
  * light DOM (hidden by the Shadow DOM — pure data carriers). The `label`
45
69
  * attribute becomes the step heading; `textContent` becomes the expandable
46
- * detail. Children are merged after any prop steps.
70
+ * detail; an optional `step-id` becomes the open-set key. Children are merged
71
+ * after any prop steps.
47
72
  *
48
73
  * ```html
49
74
  * <kai-chain-of-thought>
@@ -53,9 +78,12 @@ export function parseKaiStepElement(n: Element): Step {
53
78
  * </kai-chain-of-thought>
54
79
  * ```
55
80
  */
56
- defineWebComponent<Props>('kai-chain-of-thought', {
81
+ defineWebComponent<Props, Events>('kai-chain-of-thought', {
57
82
  steps: [],
58
- }, (props, { element }) => {
83
+ type: undefined,
84
+ value: undefined,
85
+ defaultValue: undefined,
86
+ }, (props, { element, dispatch, expose }) => {
59
87
  // Read declarative <kai-step> children from light DOM.
60
88
  // Shadow DOM with no <slot> suppresses them visually — they're invisible data carriers.
61
89
  const [slottedSteps, setSlottedSteps] = createSignal<Step[]>([]);
@@ -73,20 +101,37 @@ defineWebComponent<Props>('kai-chain-of-thought', {
73
101
  // Prop steps first; declarative children appended after.
74
102
  const allSteps = () => [...props.steps, ...slottedSteps()];
75
103
 
104
+ // ── Imperative API (instance methods on the host) ──────────────────────────
105
+ // Pattern C: the Accordion component owns the open-set; the facade captures its
106
+ // controller and exposes index-based methods. Every setter routes through the
107
+ // component's onValueChange (handleValueChange below) — the single emit point —
108
+ // so user clicks AND method calls both fire kai-value-change. No prop collisions:
109
+ // the only props are steps/type/value/defaultValue.
110
+ let controller: ChainOfThoughtController | undefined;
111
+ expose({
112
+ /** Open one step's detail by index, or — with no arg — ALL steps. In `single`
113
+ * mode opening one step closes the others (expand-all keeps the last). */
114
+ expand: (index?: number) => controller?.expand(index),
115
+ /** Close one step's detail by index, or — with no arg — ALL steps. */
116
+ collapse: (index?: number) => controller?.collapse(index),
117
+ /** Flip one step's open state by index. */
118
+ toggle: (index?: number) => controller?.toggle(index),
119
+ });
120
+
121
+ // Single emit point for the open set — both user clicks and the methods above
122
+ // flow through the component's onValueChange to here.
123
+ const handleValueChange = (value: string | string[]) => {
124
+ dispatch('kai-value-change', { value });
125
+ };
126
+
76
127
  return (
77
- <ChainOfThought>
78
- <For each={allSteps()}>
79
- {(step, i) => (
80
- <ChainOfThoughtStep isLast={i() === allSteps().length - 1}>
81
- <ChainOfThoughtTrigger>{step.label}</ChainOfThoughtTrigger>
82
- <Show when={step.content}>
83
- <ChainOfThoughtContent>
84
- <ChainOfThoughtItem>{step.content}</ChainOfThoughtItem>
85
- </ChainOfThoughtContent>
86
- </Show>
87
- </ChainOfThoughtStep>
88
- )}
89
- </For>
90
- </ChainOfThought>
128
+ <ChainOfThoughtAccordion
129
+ steps={allSteps()}
130
+ type={props.type as ChainOfThoughtType | undefined}
131
+ value={props.value as string | string[] | undefined}
132
+ defaultValue={props.defaultValue as string | string[] | undefined}
133
+ onValueChange={handleValueChange}
134
+ controllerRef={(c) => (controller = c)}
135
+ />
91
136
  );
92
137
  });