@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
@@ -8,17 +8,20 @@ import {
8
8
  createMemo,
9
9
  createEffect,
10
10
  on,
11
+ onMount,
11
12
  ErrorBoundary,
12
13
  createUniqueId,
13
14
  } from 'solid-js';
14
15
  import { cn } from '../utils/cn';
15
16
  import { Button } from '../ui/button';
17
+ import { ProgressBar } from '../ui/progress-bar';
16
18
  import { Card } from './card';
19
+ import { DismissedStub } from './dismissed-stub';
17
20
  import type { CardEnvelope, CardEvent, CardHost, CardResolution } from '../primitives/card-contract';
18
21
  import { useCardResolution } from './use-card-resolution';
19
22
  import { emitCardEvent } from '../primitives/card-routing';
20
23
  import { useCardHost } from '../primitives/card-host';
21
- import { Check } from 'lucide-solid';
24
+ import { Check, Circle, CircleCheck, X } from 'lucide-solid';
22
25
 
23
26
  // ─────────────────────────────────────────────────────────────────────────────
24
27
  // Types (tasks.schema.json) — see src/primitives/card-schemas/tasks.schema.json
@@ -33,7 +36,15 @@ export interface TasksTask {
33
36
  }
34
37
 
35
38
  export interface TasksCardData {
36
- mode?: 'select'; // future: 'select' | 'progress'
39
+ /**
40
+ * `select` (default) = checkbox rows + a confirm button that emits the contract
41
+ * `submit`. `progress` = an onboarding/checklist look: a header `done / total`
42
+ * count, circular indicators, per-item title + muted description, and NO confirm
43
+ * button (checking a row is itself the terminal action). Both share the same
44
+ * selection model (toggle by id, the `max` gate, `kai-value-change`); `progress`
45
+ * is purely a presentational variant.
46
+ */
47
+ mode?: 'select' | 'progress';
37
48
  heading?: string;
38
49
  tasks: TasksTask[]; // >=1
39
50
  selectAll?: boolean;
@@ -41,6 +52,7 @@ export interface TasksCardData {
41
52
  allowEmpty?: boolean;
42
53
  min?: number;
43
54
  max?: number;
55
+ dismissible?: boolean; // show a close affordance that emits `dismiss`
44
56
  }
45
57
 
46
58
  export interface TasksCardResult {
@@ -121,6 +133,16 @@ export function showSelectAll(data: TasksCardData, tasks: TasksTask[]): boolean
121
133
  return true;
122
134
  }
123
135
 
136
+ /** Whether the card is in the onboarding-checklist `progress` look (no confirm). */
137
+ export function isProgressMode(data: TasksCardData): boolean {
138
+ return data.mode === 'progress';
139
+ }
140
+
141
+ /** The header progress count (`done` checked / `total` rows) for `progress` mode. */
142
+ export function progressCount(tasks: TasksTask[], selected: Set<string>): { done: number; total: number } {
143
+ return { done: tasks.filter((t) => selected.has(t.id)).length, total: tasks.length };
144
+ }
145
+
124
146
  /** Whether confirm is enabled for the current selection count. */
125
147
  export function canConfirm(data: TasksCardData, count: number): boolean {
126
148
  const min = data.min ?? (data.allowEmpty ? 0 : 1);
@@ -147,6 +169,24 @@ export function confirmReason(data: TasksCardData, count: number): string | unde
147
169
  // The <TasksCard> component.
148
170
  // ─────────────────────────────────────────────────────────────────────────────
149
171
 
172
+ /** Imperative handle exposed via `controllerRef` — surfaces the tasks card's latent
173
+ * selection model (set the checked ids, toggle one, confirm, focus the group,
174
+ * dismiss/reopen) so the `<kai-tasks>` facade can forward them as instance methods. */
175
+ export interface TasksCardController {
176
+ /** Set the checked ids (local-only, no emit), respecting disabled/max. No arg = select all toggleable rows. */
177
+ select(taskIds?: string[]): void;
178
+ /** Toggle one task by id, honoring the max gate. */
179
+ toggle(taskId: string, checked?: boolean): void;
180
+ /** Confirm the current selection (only when allowed) — emits `submit` + resolves. */
181
+ send(): void;
182
+ /** Focus the task group (select-all checkbox if shown, else the first row). */
183
+ focus(options?: FocusOptions): void;
184
+ /** Trigger the dismiss path (emit `dismiss` + collapse to the re-openable stub). */
185
+ dismiss(): void;
186
+ /** Re-open a dismissed card from its stub (emit `reopen`). */
187
+ reopen(): void;
188
+ }
189
+
150
190
  export interface TasksCardProps {
151
191
  /** The tasks definition (CardEnvelope.data). */
152
192
  data?: TasksCardData;
@@ -162,6 +202,20 @@ export interface TasksCardProps {
162
202
  class?: string;
163
203
  /** When set, render the chromed read-only summary instead of the interactive controls. */
164
204
  resolution?: CardResolution;
205
+ /** Controlled selection (task ids) — when set, this wins over internal state. */
206
+ value?: string[];
207
+ /** Uncontrolled initial selection (task ids), overlaying per-task `checked`. */
208
+ defaultValue?: string[];
209
+ /** Freeze the whole list + Confirm. */
210
+ disabled?: boolean;
211
+ /** Display-only: rows can't be toggled and show the default cursor (no pointer,
212
+ * no hover background, no focus ring). Keeps the visual content as-is — this only
213
+ * drops the interactive affordances + a11y exposure. */
214
+ readonly?: boolean;
215
+ /** Fires on every selection change with the selected ids (distinct from submit). */
216
+ onValueChange?: (payload: { value: string[] }) => void;
217
+ /** Receive the imperative controller once mounted. */
218
+ controllerRef?: (controller: TasksCardController) => void;
165
219
  }
166
220
 
167
221
  const DEFAULT_DATA: TasksCardData = { tasks: [] };
@@ -175,7 +229,10 @@ const DEFAULT_DATA: TasksCardData = { tasks: [] };
175
229
  */
176
230
  export function TasksCard(props: TasksCardProps): JSX.Element {
177
231
  const merged = mergeProps({ cardId: 'kai-tasks' }, props);
178
- const [local] = splitProps(merged, ['data', 'cardId', 'heading', 'host', 'hostElement', 'class', 'resolution']);
232
+ const [local] = splitProps(merged, [
233
+ 'data', 'cardId', 'heading', 'host', 'hostElement', 'class', 'resolution',
234
+ 'value', 'defaultValue', 'disabled', 'readonly', 'onValueChange', 'controllerRef',
235
+ ]);
179
236
 
180
237
  const ctxHost = useCardHost();
181
238
  const uid = createUniqueId();
@@ -196,16 +253,37 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
196
253
 
197
254
  const res = useCardResolution({ prop: () => local.resolution, data: () => local.data });
198
255
 
199
- // Seed selection from the tasks' initial checked state when a NEW definition arrives.
256
+ // Only ids that exist in the current task list (drop unknown ids defensively).
257
+ const validIds = (ids: string[]): string[] => {
258
+ const known = new Set(tasks().map((t) => t.id));
259
+ return ids.filter((id) => known.has(id));
260
+ };
261
+
262
+ // Seed selection from `value` (controlled) > `defaultValue` > per-task `checked`,
263
+ // when a NEW definition arrives.
200
264
  createEffect(
201
265
  on(
202
266
  () => local.data,
203
267
  () => {
204
- setSelected(new Set(initialSelected(tasks())));
268
+ const seedIds = local.value ?? local.defaultValue ?? initialSelected(tasks());
269
+ setSelected(new Set(validIds(seedIds)));
205
270
  },
206
271
  ),
207
272
  );
208
273
 
274
+ // Controlled selection: when the consumer drives `value`, mirror it into the set
275
+ // (the controlled prop wins). Deferred so mount's seed runs first.
276
+ createEffect(on(() => local.value, (v) => {
277
+ if (!v) return;
278
+ setSelected(new Set(validIds(v)));
279
+ }, { defer: true }));
280
+
281
+ // Fire the live change signal whenever the selection set changes (distinct from
282
+ // the terminal submit). Deferred so the initial seed doesn't emit.
283
+ createEffect(on(selected, (s) => {
284
+ local.onValueChange?.({ value: selectedInOrder(tasks(), s) });
285
+ }, { defer: true }));
286
+
209
287
  // ready / error lifecycle emits.
210
288
  createEffect(
211
289
  on(valid, (ok) => {
@@ -214,28 +292,41 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
214
292
  }),
215
293
  );
216
294
 
295
+ const groupDisabled = (): boolean => local.disabled === true;
296
+ // Display-only: block all toggling/confirm and drop the interactive affordances,
297
+ // without the dimmed/`disabled` look.
298
+ const readOnly = (): boolean => local.readonly === true;
299
+
217
300
  const count = createMemo(() => selected().size);
301
+ // `progress` mode = the onboarding-checklist look: a header `done / total`
302
+ // count, circular indicators, no confirm button. Same selection model.
303
+ const progress = createMemo(() => isProgressMode(data()));
304
+ const progressN = createMemo(() => progressCount(tasks(), selected()));
218
305
  const confirmLabel = () => data().confirmLabel ?? 'Confirm';
219
306
  const masterState = createMemo(() => selectAllState(tasks(), selected()));
220
307
  const showMaster = createMemo(() => showSelectAll(data(), tasks()));
221
308
  const reason = createMemo(() => confirmReason(data(), count()));
222
- const confirmEnabled = createMemo(() => canConfirm(data(), count()) && !res.isResolved());
309
+ const confirmEnabled = createMemo(() => canConfirm(data(), count()) && !res.isResolved() && !groupDisabled() && !readOnly());
223
310
 
224
- const toggle = (id: string, on: boolean): void => {
225
- if (res.isResolved()) return;
226
- const next = new Set(selected());
311
+ // Apply one id to a selection set, honoring the max gate (mutates+returns `next`).
312
+ const applyToggle = (next: Set<string>, id: string, on: boolean): Set<string> => {
227
313
  if (on) {
228
314
  // Respect max: block adding past max.
229
- if (isMaxReached(data(), next.size) && !next.has(id)) return;
315
+ if (isMaxReached(data(), next.size) && !next.has(id)) return next;
230
316
  next.add(id);
231
317
  } else {
232
318
  next.delete(id);
233
319
  }
234
- setSelected(next);
320
+ return next;
321
+ };
322
+
323
+ const toggle = (id: string, on: boolean): void => {
324
+ if (res.isResolved() || groupDisabled() || readOnly()) return;
325
+ setSelected(applyToggle(new Set(selected()), id, on));
235
326
  };
236
327
 
237
328
  const toggleAll = (on: boolean): void => {
238
- if (res.isResolved()) return;
329
+ if (res.isResolved() || groupDisabled() || readOnly()) return;
239
330
  const next = new Set(selected());
240
331
  for (const id of toggleableIds(tasks())) {
241
332
  if (on) next.add(id);
@@ -251,11 +342,58 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
251
342
  res.setLocal({ kind: 'submit', data: result });
252
343
  };
253
344
 
254
- // Surface the resolved state for host styling.
345
+ // Dismiss: emit `dismiss` AND optimistically flip to a `dismissed` resolution so
346
+ // the card collapses to its re-openable stub immediately.
347
+ const onDismiss = (): void => {
348
+ if (res.isResolved()) return;
349
+ emit({ kind: 'dismiss', cardId: local.cardId });
350
+ res.setLocal({ kind: 'dismissed' });
351
+ };
352
+ const onReopen = (): void => emit({ kind: 'reopen', cardId: local.cardId });
353
+
354
+ // Imperative controller (Pattern C): hand the facade a handle over the tasks
355
+ // card's latent selection model. select sets the checked ids local-only (no
356
+ // submit); toggle drives one row; send confirms (same path as Confirm); focus
357
+ // targets the group; dismiss/reopen drive the stub.
358
+ onMount(() => {
359
+ local.controllerRef?.({
360
+ select: (taskIds) => {
361
+ if (res.isResolved() || groupDisabled() || readOnly()) return;
362
+ if (taskIds === undefined) { toggleAll(true); return; }
363
+ // Build the set fresh, honoring max + disabled per id (skip disabled rows).
364
+ const next = new Set<string>();
365
+ const toggleable = new Set(toggleableIds(tasks()));
366
+ for (const id of validIds(taskIds)) {
367
+ if (!toggleable.has(id)) continue; // skip per-task-disabled rows
368
+ applyToggle(next, id, true);
369
+ }
370
+ setSelected(next);
371
+ },
372
+ toggle: (taskId, checked) => {
373
+ // No explicit `checked` → flip the current state.
374
+ const on = checked ?? !selected().has(taskId);
375
+ toggle(taskId, on);
376
+ },
377
+ send: () => onConfirm(),
378
+ focus: (options) => {
379
+ const root = local.hostElement?.shadowRoot ?? document;
380
+ const group = root.querySelector<HTMLElement>('[role="group"]');
381
+ // Prefer the select-all checkbox (it's the first labelled input), else the
382
+ // first row's checkbox; fall back to the group container itself.
383
+ const firstInput = group?.querySelector<HTMLElement>('input[type="checkbox"]');
384
+ (firstInput ?? group)?.focus(options);
385
+ },
386
+ dismiss: () => onDismiss(),
387
+ reopen: () => onReopen(),
388
+ });
389
+ });
390
+
391
+ // Surface the resolved state for host styling. Only a `submit` resolution is the
392
+ // "submitted" state; a deferred `dismissed` (or `expired`) is not.
255
393
  createEffect(() => {
256
394
  const el = local.hostElement;
257
395
  if (!el) return;
258
- if (res.isResolved()) el.setAttribute('data-kai-resolved', 'submitted');
396
+ if (res.resolution()?.kind === 'submit') el.setAttribute('data-kai-resolved', 'submitted');
259
397
  else el.removeAttribute('data-kai-resolved');
260
398
  });
261
399
 
@@ -271,6 +409,9 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
271
409
 
272
410
  const reasonId = `kai-tl-reason-${uid}`;
273
411
  const countId = `kai-tl-count-${uid}`;
412
+ const progressCountId = `kai-tl-progress-${uid}`;
413
+ const progressHeadingId = `kai-tl-heading-${uid}`;
414
+ const headingText = () => local.heading ?? local.data?.heading;
274
415
 
275
416
  return (
276
417
  <Show when={valid()} fallback={<Card heading={local.heading} errorMessage={errorMessage()} />}>
@@ -280,11 +421,33 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
280
421
  return <Card heading={local.heading} errorMessage="The card failed to render." />;
281
422
  }}
282
423
  >
424
+ <Show
425
+ when={!res.isDeferred()}
426
+ fallback={
427
+ <DismissedStub type={TASKS_CARD_TYPE} title={local.heading ?? local.data?.heading} onReopen={onReopen} />
428
+ }
429
+ >
283
430
  <Card
284
- heading={local.heading ?? local.data?.heading}
431
+ // In `progress` mode the heading + count render as a custom in-body row
432
+ // (so the count can sit right-aligned beside the heading), so the Card
433
+ // chrome's own heading is suppressed.
434
+ heading={progress() ? undefined : headingText()}
285
435
  actions={
286
- res.isResolved() ? undefined : (
436
+ // `progress` mode is confirm-less: checking a row IS the action.
437
+ // `readonly` is display-only, so there's no confirm/dismiss row either.
438
+ progress() || res.isResolved() || readOnly() ? undefined : (
287
439
  <div class="flex w-full flex-wrap items-center justify-between gap-2">
440
+ <Show when={local.data?.dismissible === true}>
441
+ <Button
442
+ type="button"
443
+ variant="ghost"
444
+ size="icon-sm"
445
+ aria-label="Dismiss"
446
+ onClick={onDismiss}
447
+ >
448
+ <X size={16} aria-hidden="true" />
449
+ </Button>
450
+ </Show>
288
451
  <span id={countId} aria-live="polite" class="text-xs text-muted-foreground">
289
452
  {count()} selected
290
453
  </span>
@@ -311,9 +474,31 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
311
474
  when={!res.isResolved()}
312
475
  fallback={<TasksResolved summary={resolvedSummary()!} optimistic={res.isOptimistic()} />}
313
476
  >
477
+ <Show when={progress()}>
478
+ <ProgressChecklist
479
+ heading={headingText()}
480
+ headingId={progressHeadingId}
481
+ countId={progressCountId}
482
+ done={progressN().done}
483
+ total={progressN().total}
484
+ tasks={tasks()}
485
+ uid={uid}
486
+ isChecked={(id) => selected().has(id)}
487
+ isBlocked={(task) =>
488
+ groupDisabled() || task.disabled === true ||
489
+ (!selected().has(task.id) && isMaxReached(data(), count()))
490
+ }
491
+ onToggle={(id, on) => toggle(id, on)}
492
+ groupClass={local.class}
493
+ maxNote={data().max !== undefined ? data().max : undefined}
494
+ readonly={readOnly()}
495
+ />
496
+ </Show>
497
+ <Show when={!progress()}>
314
498
  <div
315
499
  role="group"
316
500
  aria-label={local.heading ?? local.data?.heading ?? 'Tasks'}
501
+ aria-readonly={readOnly() ? 'true' : undefined}
317
502
  class={cn('flex flex-col', local.class)}
318
503
  onKeyDown={(e) => {
319
504
  // Enter anywhere in the card (off a checkbox) confirms when enabled.
@@ -330,16 +515,20 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
330
515
  return (
331
516
  <label
332
517
  class={cn(
333
- 'flex cursor-pointer items-center gap-3 px-3 py-2.5 text-sm font-medium transition-colors',
518
+ 'flex items-center gap-3 px-3 py-2.5 text-sm font-medium transition-colors',
519
+ readOnly() ? 'cursor-default' : 'cursor-pointer',
334
520
  masterState() === 'checked'
335
521
  ? 'bg-accent text-accent-foreground'
336
- : 'text-foreground hover:bg-muted/50',
522
+ : readOnly()
523
+ ? 'text-foreground'
524
+ : 'text-foreground hover:bg-muted/50',
337
525
  )}
338
526
  >
339
527
  <input
340
528
  type="checkbox"
341
529
  class="kai-checkbox"
342
530
  checked={masterState() === 'checked'}
531
+ disabled={groupDisabled() || readOnly()}
343
532
  aria-checked={indeterminate() ? 'mixed' : masterState() === 'checked'}
344
533
  ref={(el) => {
345
534
  createEffect(() => {
@@ -358,15 +547,17 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
358
547
  {(task) => {
359
548
  const checked = () => selected().has(task.id);
360
549
  const blocked = () =>
361
- task.disabled || (!checked() && isMaxReached(data(), count()));
550
+ groupDisabled() || task.disabled || (!checked() && isMaxReached(data(), count()));
362
551
  const descId = `kai-tl-desc-${uid}-${task.id}`;
363
552
  return (
364
553
  <label
365
554
  class={cn(
366
555
  'flex items-start gap-3 px-3 py-2.5 text-sm transition-colors',
367
- blocked()
368
- ? 'cursor-not-allowed opacity-60'
369
- : 'cursor-pointer hover:bg-muted/50',
556
+ readOnly()
557
+ ? 'cursor-default'
558
+ : blocked()
559
+ ? 'cursor-not-allowed opacity-60'
560
+ : 'cursor-pointer hover:bg-muted/50',
370
561
  checked() && !blocked()
371
562
  ? 'bg-accent font-medium text-accent-foreground'
372
563
  : 'text-foreground',
@@ -377,7 +568,7 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
377
568
  type="checkbox"
378
569
  class="kai-checkbox mt-0.5"
379
570
  checked={checked()}
380
- disabled={blocked()}
571
+ disabled={blocked() || readOnly()}
381
572
  aria-disabled={blocked() ? 'true' : undefined}
382
573
  aria-describedby={task.description ? descId : undefined}
383
574
  onChange={(e) => toggle(task.id, e.currentTarget.checked)}
@@ -400,13 +591,173 @@ export function TasksCard(props: TasksCardProps): JSX.Element {
400
591
  <p class="pt-1 text-xs text-muted-foreground">Up to {data().max} selected.</p>
401
592
  </Show>
402
593
  </div>
594
+ </Show>
403
595
  </Show>
404
596
  </Card>
597
+ </Show>
405
598
  </ErrorBoundary>
406
599
  </Show>
407
600
  );
408
601
  }
409
602
 
603
+ // ─────────────────────────────────────────────────────────────────────────────
604
+ // Onboarding-checklist (`mode: 'progress'`) presenter: a header `done / total`
605
+ // count + circular indicators + per-item title/description, no confirm button.
606
+ // Drives the same selection model, where toggling a row IS the action.
607
+ // ─────────────────────────────────────────────────────────────────────────────
608
+
609
+ function ProgressChecklist(props: {
610
+ heading?: string;
611
+ headingId: string;
612
+ countId: string;
613
+ done: number;
614
+ total: number;
615
+ tasks: TasksTask[];
616
+ uid: string;
617
+ isChecked: (id: string) => boolean;
618
+ isBlocked: (task: TasksTask) => boolean;
619
+ onToggle: (id: string, on: boolean) => void;
620
+ groupClass?: string;
621
+ maxNote?: number;
622
+ /** Display-only: rows aren't focusable/toggleable and show the default cursor. */
623
+ readonly?: boolean;
624
+ }): JSX.Element {
625
+ return (
626
+ <div class={cn('flex flex-col gap-3', props.groupClass)}>
627
+ <Show when={props.heading}>
628
+ <div class="flex items-center justify-between gap-3">
629
+ <span id={props.headingId} class="text-sm font-medium text-foreground">
630
+ {props.heading}
631
+ </span>
632
+ <span
633
+ id={props.countId}
634
+ aria-live="polite"
635
+ class="shrink-0 text-sm font-medium tabular-nums text-muted-foreground"
636
+ >
637
+ {props.done} / {props.total}
638
+ </span>
639
+ </div>
640
+ </Show>
641
+
642
+ {/* Thin progress bar under the heading: filled to done / total. Named off the
643
+ checklist heading (no duplicate caption), or a generic label when headless. */}
644
+ <ProgressBar
645
+ value={props.done}
646
+ max={props.total}
647
+ tone="success"
648
+ aria-labelledby={props.heading ? props.headingId : undefined}
649
+ aria-label={props.heading ? undefined : 'Task progress'}
650
+ />
651
+
652
+ <ul
653
+ aria-labelledby={props.heading ? props.headingId : undefined}
654
+ aria-label={props.heading ? undefined : 'Checklist'}
655
+ aria-readonly={props.readonly ? 'true' : undefined}
656
+ class="flex flex-col gap-1"
657
+ >
658
+ <For each={props.tasks}>
659
+ {(task) => {
660
+ const checked = () => props.isChecked(task.id);
661
+ const blocked = () => props.isBlocked(task);
662
+ const descId = `kai-tl-pdesc-${props.uid}-${task.id}`;
663
+ return (
664
+ <li>
665
+ <label
666
+ class={cn(
667
+ 'group flex items-start gap-3 rounded-lg px-2.5 py-2 text-sm transition-colors',
668
+ // Keyboard focus ring (kit standard, inset so it stays within the
669
+ // row). focus-visible only, so a mouse click that parks focus on the
670
+ // row doesn't leave a noisy persistent outline — and it makes a
671
+ // Tab-focused completed row's open description perceivable. Dropped
672
+ // entirely when readonly (the row isn't focusable then).
673
+ !props.readonly &&
674
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring',
675
+ props.readonly
676
+ ? 'cursor-default'
677
+ : blocked()
678
+ ? 'cursor-not-allowed opacity-60'
679
+ : 'cursor-pointer hover:bg-muted/50',
680
+ )}
681
+ data-task-id={task.id}
682
+ // Completed rows hide their description until hover/focus, so make the
683
+ // row itself focusable to drive the focus-reveal (group-focus-within).
684
+ // Incomplete rows — and every row when readonly — stay unfocusable.
685
+ // Expose the label + description to AT.
686
+ tabindex={!props.readonly && checked() ? 0 : undefined}
687
+ aria-label={checked() ? task.label : undefined}
688
+ aria-describedby={checked() && task.description ? descId : undefined}
689
+ >
690
+ <input
691
+ type="checkbox"
692
+ class="sr-only"
693
+ checked={checked()}
694
+ disabled={blocked() || props.readonly}
695
+ aria-disabled={blocked() ? 'true' : undefined}
696
+ aria-describedby={task.description ? descId : undefined}
697
+ onChange={(e) => props.onToggle(task.id, e.currentTarget.checked)}
698
+ />
699
+ <span
700
+ class={cn(
701
+ 'mt-0.5 shrink-0 text-muted-foreground',
702
+ // Completed rows: the check gently scales on hover.
703
+ checked() && 'motion-safe:transition-transform motion-safe:group-hover:scale-110',
704
+ )}
705
+ aria-hidden="true"
706
+ >
707
+ <Show
708
+ when={checked()}
709
+ fallback={<Circle size={18} />}
710
+ >
711
+ <CircleCheck size={18} class="text-foreground" />
712
+ </Show>
713
+ </span>
714
+ <span class="flex min-w-0 flex-col gap-0.5">
715
+ <span
716
+ class={cn(
717
+ 'font-medium text-foreground',
718
+ // Completed: strike through + muted, brightening on hover.
719
+ checked() && 'line-through opacity-70 motion-safe:transition-opacity motion-safe:group-hover:opacity-100',
720
+ )}
721
+ >
722
+ {task.label}
723
+ </span>
724
+ <Show when={task.description}>
725
+ <Show
726
+ when={checked()}
727
+ fallback={
728
+ <span id={descId} class="text-xs font-normal text-muted-foreground">
729
+ {task.description}
730
+ </span>
731
+ }
732
+ >
733
+ {/* Completed: collapse the description and reveal it on hover or
734
+ keyboard focus via the grid-rows height trick. Height-collapse
735
+ keeps the text in the DOM + a11y tree (unlike display:none). */}
736
+ <div class="grid grid-rows-[0fr] group-hover:grid-rows-[1fr] group-focus-within:grid-rows-[1fr] motion-safe:transition-[grid-template-rows] motion-safe:duration-200">
737
+ <span
738
+ id={descId}
739
+ class="overflow-hidden text-xs font-normal text-muted-foreground opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 motion-safe:transition-opacity"
740
+ >
741
+ {task.description}
742
+ </span>
743
+ </div>
744
+ </Show>
745
+ </Show>
746
+ </span>
747
+ </label>
748
+ </li>
749
+ );
750
+ }}
751
+ </For>
752
+ </ul>
753
+
754
+ <Show when={props.maxNote !== undefined}>
755
+ <p class="text-xs text-muted-foreground">Up to {props.maxNote} selected.</p>
756
+ </Show>
757
+ </div>
758
+ );
759
+ }
760
+
410
761
  // ─────────────────────────────────────────────────────────────────────────────
411
762
  // Read-only resolved summary presenter.
412
763
  // ─────────────────────────────────────────────────────────────────────────────