@kitn.ai/ui 0.26.0 → 0.28.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 (488) hide show
  1. package/README.md +25 -6
  2. package/bin/mcp.js +16 -3
  3. package/bin/route.js +23 -0
  4. package/bin/route.test.js +58 -0
  5. package/dist/{elements/chunks/Icon--Y8vsFal.js → Icon-DObhsRtm.js} +1 -1
  6. package/dist/action-icons-CcgNN2oT.js +1 -0
  7. package/dist/arrow-down-CjRU3JgV.js +1 -0
  8. package/dist/arrow-left-Bnpb1UEW.js +1 -0
  9. package/dist/artifact-Bwt7OgcR.js +1 -0
  10. package/dist/assets/dev-5XzXYR21.js +91 -0
  11. package/dist/attachments-Qr4kg-2b.js +1 -0
  12. package/dist/{elements/chunks/audio-visualizer-D7lB6mvR.js → audio-visualizer-DToYdfSc.js} +1 -1
  13. package/dist/badge-CdEu_jn2.js +1 -0
  14. package/dist/bash-InADTalH.js +1 -6
  15. package/dist/bell-DQAAOpDz.js +1 -0
  16. package/dist/{elements/chunks/button-flUbeufF.js → button-DkuOnGLy.js} +1 -1
  17. package/dist/card-renderer-Jx70m6_l.js +1 -0
  18. package/dist/card-routing-0YidER_3.js +1 -0
  19. package/dist/check-njkVdZu2.js +1 -0
  20. package/dist/checkbox-D7iRB3nL.js +1 -0
  21. package/dist/checkbox-group-B2_rpoPM.js +1 -0
  22. package/dist/chevron-down-B72s6PXR.js +1 -0
  23. package/dist/chevron-right-BatuHzUm.js +1 -0
  24. package/dist/choice-card-m0BYqqOK.js +1 -0
  25. package/dist/circle-check-B62pODB3.js +1 -0
  26. package/dist/circle-x-BPG0iPst.js +1 -0
  27. package/dist/circle-zx0ByzY9.js +1 -0
  28. package/dist/{elements/chunks/cn-CU7UAWzk.js → cn-DN5AWfiS.js} +1 -1
  29. package/dist/code-block-ClMLKb7C.js +1 -0
  30. package/dist/{elements/chunks/collapsible-BzbXpPzr.js → collapsible-B4DlWicL.js} +1 -1
  31. package/dist/components/attachment-types.d.ts +7 -0
  32. package/dist/components/audio-visualizer/fit-scale.d.ts +1 -1
  33. package/dist/components/card-renderer.d.ts +13 -0
  34. package/dist/components/card.d.ts +4 -0
  35. package/dist/components/chat-thread.d.ts +135 -2
  36. package/dist/components/conversation-item.d.ts +35 -7
  37. package/dist/components/conversation-list.d.ts +17 -5
  38. package/dist/components/conversation-panel.d.ts +29 -0
  39. package/dist/components/form-widgets.d.ts +67 -2
  40. package/dist/components/form.d.ts +48 -1
  41. package/dist/components/home-panel.d.ts +34 -0
  42. package/dist/components/message.d.ts +25 -3
  43. package/dist/components/reasoning.d.ts +6 -0
  44. package/dist/components/scroll-button.d.ts +11 -0
  45. package/dist/components/thread.d.ts +5 -0
  46. package/dist/components/tool-types.d.ts +9 -0
  47. package/dist/components/widget-tab-bar.d.ts +16 -0
  48. package/dist/composer-sQ0HcvyG.js +106 -0
  49. package/dist/confirm-card-rQWDQsnC.js +1 -0
  50. package/dist/construct-cli.es.js +1337 -0
  51. package/dist/{elements/chunks/context-VLIL3sJ-.js → context-0kg4ZX1J.js} +1 -1
  52. package/dist/controllable-CnGpMF6r.js +1 -0
  53. package/dist/conversation-item-BxwQLaFJ.js +1 -0
  54. package/dist/conversation-list-BCfGN1JU.js +1 -0
  55. package/dist/copy-n9u9rqpi.js +1 -0
  56. package/dist/core-AYMC6_lb.js +12 -5874
  57. package/dist/{create-tween-BFT6c-Y8.js → create-tween-C-q-JCM-.js} +1 -1
  58. package/dist/{create-tween-CJNlzoaO.js → create-tween-CRrJXxBd.js} +1 -1
  59. package/dist/{create-tween-CQED4T0g.js → create-tween-DZ3RRDHD.js} +1 -1
  60. package/dist/{elements/chunks/create-tween-c4Z8TDYz.js → create-tween-uPkArjIG.js} +2 -2
  61. package/dist/css-M7EaDHN_.js +1 -6
  62. package/dist/custom-elements.json +1433 -202
  63. package/dist/default-input-CaMrJkgH.js +1 -0
  64. package/dist/define-By-uL588.js +1 -0
  65. package/dist/define.d.ts +4 -0
  66. package/dist/define.js +510 -0
  67. package/dist/define.server.d.ts +5 -0
  68. package/dist/define.server.js +506 -0
  69. package/dist/{elements/chunks/disclosure-CcNbyLy0.js → disclosure-WUImBbDv.js} +1 -1
  70. package/dist/{elements/chunks/dropdown-BgWTthUx.js → dropdown-wZVeJOMd.js} +1 -1
  71. package/dist/elements/agent-card.js +1 -1
  72. package/dist/elements/artifact.js +1 -1
  73. package/dist/elements/attachments.js +1 -1
  74. package/dist/elements/audio-visualizer.js +1 -1
  75. package/dist/elements/autoloader.js +1 -1
  76. package/dist/elements/avatar.js +1 -1
  77. package/dist/elements/badge.js +1 -1
  78. package/dist/elements/button.js +1 -1
  79. package/dist/elements/card.js +1 -1
  80. package/dist/elements/cards.js +1 -1
  81. package/dist/elements/chain-of-thought.js +1 -1
  82. package/dist/elements/chat-scope-picker.js +1 -1
  83. package/dist/elements/chat-workspace.js +1 -1
  84. package/dist/elements/chat.js +1 -1
  85. package/dist/elements/checkbox-group.d.ts +1 -0
  86. package/dist/elements/checkbox-group.js +1 -0
  87. package/dist/elements/checkbox.d.ts +1 -0
  88. package/dist/elements/checkbox.js +1 -0
  89. package/dist/elements/checkpoint.js +1 -1
  90. package/dist/elements/choice.js +1 -1
  91. package/dist/elements/coachmark.js +1 -1
  92. package/dist/elements/code-block.js +1 -1
  93. package/dist/elements/command.js +1 -1
  94. package/dist/elements/compare.js +1 -1
  95. package/dist/elements/composer.js +1 -1
  96. package/dist/elements/confirm-card.js +1 -1
  97. package/dist/elements/context-meter.js +1 -1
  98. package/dist/elements/conversation-item.js +1 -1
  99. package/dist/elements/conversation-list.js +1 -1
  100. package/dist/elements/define-entry.d.ts +12 -0
  101. package/dist/elements/dialog.js +1 -1
  102. package/dist/elements/dock.js +102 -8
  103. package/dist/elements/dropdown.js +1 -1
  104. package/dist/elements/editable-label.js +1 -1
  105. package/dist/elements/element-data-types.d.ts +37 -0
  106. package/dist/elements/embed.js +1 -1
  107. package/dist/elements/empty.js +1 -1
  108. package/dist/elements/feedback-bar.js +1 -1
  109. package/dist/elements/file-tree.js +1 -1
  110. package/dist/elements/file-upload.js +1 -1
  111. package/dist/elements/form.js +1 -1
  112. package/dist/elements/hover-card.js +1 -1
  113. package/dist/elements/icon.js +1 -1
  114. package/dist/elements/image.js +1 -1
  115. package/dist/elements/input.js +1 -1
  116. package/dist/elements/kbd.js +1 -1
  117. package/dist/elements/link-preview.js +1 -1
  118. package/dist/elements/loader.js +1 -1
  119. package/dist/elements/markdown.js +1 -1
  120. package/dist/elements/menu.js +1 -1
  121. package/dist/elements/message-skills.js +1 -1
  122. package/dist/elements/message.js +1 -1
  123. package/dist/elements/model-switcher.js +1 -1
  124. package/dist/elements/nav.js +1 -1
  125. package/dist/elements/notice.js +1 -1
  126. package/dist/elements/pane-grid.d.ts +1 -0
  127. package/dist/elements/pane-grid.js +1 -0
  128. package/dist/elements/pane-group.js +1 -1
  129. package/dist/elements/pane.js +1 -1
  130. package/dist/elements/popover.js +1 -1
  131. package/dist/elements/progress-bar.js +1 -1
  132. package/dist/elements/prompt-dock.js +1 -1
  133. package/dist/elements/prompt-input.js +1 -1
  134. package/dist/elements/prompt-suggestions.js +1 -1
  135. package/dist/elements/radio-group.d.ts +1 -0
  136. package/dist/elements/radio-group.js +1 -0
  137. package/dist/elements/reasoning.js +1 -1
  138. package/dist/elements/remote.js +1 -1
  139. package/dist/elements/resizable.js +1 -1
  140. package/dist/elements/response-stream.js +2 -2
  141. package/dist/elements/screen.js +1 -1
  142. package/dist/elements/scroll-area.js +1 -1
  143. package/dist/elements/scroll-button.js +1 -1
  144. package/dist/elements/search.js +1 -1
  145. package/dist/elements/segmented.js +1 -1
  146. package/dist/elements/select.d.ts +1 -0
  147. package/dist/elements/select.js +1 -0
  148. package/dist/elements/separator.js +1 -1
  149. package/dist/elements/setting-item.js +1 -1
  150. package/dist/elements/settings-group.js +1 -1
  151. package/dist/elements/skeleton.js +1 -1
  152. package/dist/elements/slider.d.ts +1 -0
  153. package/dist/elements/slider.js +1 -0
  154. package/dist/elements/slots.d.ts +1 -1
  155. package/dist/elements/source.js +1 -1
  156. package/dist/elements/status.js +1 -1
  157. package/dist/elements/switch.js +1 -1
  158. package/dist/elements/tabs.js +1 -1
  159. package/dist/elements/tasks.js +1 -1
  160. package/dist/elements/text-shimmer.js +1 -1
  161. package/dist/elements/thinking-bar.js +1 -1
  162. package/dist/elements/thread.js +1 -1
  163. package/dist/elements/toast.js +1 -1
  164. package/dist/elements/tool.js +1 -1
  165. package/dist/elements/tooltip.js +1 -1
  166. package/dist/elements/voice-input.js +1 -1
  167. package/dist/elements/voice-output.js +1 -1
  168. package/dist/elements.d.ts +380 -26
  169. package/dist/{elements/chunks/ellipsis-7gU33mL2.js → ellipsis-CbOpJnU3.js} +1 -1
  170. package/dist/embed-CrfjkbUG.js +1 -0
  171. package/dist/engine-javascript-vq0WuIJl.js +14 -2516
  172. package/dist/{elements/chunks/external-link-CSOEsNlx.js → external-link-ByXAwBBQ.js} +1 -1
  173. package/dist/file-text-DMib2qwt.js +1 -0
  174. package/dist/{elements/chunks/file-tree-zvB2i7P9.js → file-tree-CJqM2aP7.js} +1 -1
  175. package/dist/folder-_BAb929C.js +1 -0
  176. package/dist/form-DSZgZQZk.js +1 -0
  177. package/dist/github-dark-dimmed-DUshB20C.js +1 -4
  178. package/dist/github-light-JYsPkUQd.js +1 -4
  179. package/dist/hover-card-BQbul9eq.js +1 -0
  180. package/dist/html-CPZ3oZQ7.js +1 -10
  181. package/dist/icon-CdcfRhYI.js +1 -0
  182. package/dist/{elements/chunks/index-BCRhi84a.js → index-xu_pdcPi.js} +1 -1
  183. package/dist/index.d.ts +4 -2
  184. package/dist/index.js +7474 -5857
  185. package/dist/index.server.js +5965 -4762
  186. package/dist/info-DsFjGuI_.js +1 -0
  187. package/dist/input-DKbmkMos.js +1 -0
  188. package/dist/javascript-C25yR2R2.js +1 -6
  189. package/dist/json-DxJze_jm.js +1 -6
  190. package/dist/kai.es.js +1 -1
  191. package/dist/kbd-PvdGhX4s.js +1 -0
  192. package/dist/{elements/chunks/link-preview-OQ9IEq0f.js → link-preview-DbM1866N.js} +1 -1
  193. package/dist/link-zF8PzWfF.js +1 -0
  194. package/dist/loader-BM4CEz4G.js +1 -0
  195. package/dist/{elements/chunks/markdown-DgBFaGAz.js → markdown-LMvmAyBk.js} +7 -7
  196. package/dist/mcp.es.js +1361 -81
  197. package/dist/message-BSsgvHvf.js +1 -0
  198. package/dist/message-BYZECyek.js +1 -0
  199. package/dist/message-circle-DruwObfX.js +1 -0
  200. package/dist/message-square-BG6q6mlm.js +1 -0
  201. package/dist/{elements/chunks/minimize-2-DPIUKTrT.js → minimize-2-BQRoBV1V.js} +1 -1
  202. package/dist/{elements/chunks/model-switcher-DsT8tFB0.js → model-switcher-CMpCOYcB.js} +1 -1
  203. package/dist/{elements/chunks/overlay-DuiwdXjm.js → overlay-Cb-MkyDa.js} +1 -1
  204. package/dist/panel-right-i8warFxT.js +1 -0
  205. package/dist/paperclip-ByY3UVO6.js +1 -0
  206. package/dist/play-BvKKq3fX.js +1 -0
  207. package/dist/primitives/card-data-types.d.ts +49 -0
  208. package/dist/primitives/card-routing.d.ts +1 -33
  209. package/dist/primitives/card-validate.d.ts +2 -2
  210. package/dist/primitives/chat-config.d.ts +29 -2
  211. package/dist/primitives/conversation-store.d.ts +54 -0
  212. package/dist/primitives/field-mask.d.ts +96 -0
  213. package/dist/primitives/field-semantics.d.ts +36 -0
  214. package/dist/primitives/input-mask.d.ts +46 -0
  215. package/dist/primitives/url-scheme-policy.d.ts +34 -0
  216. package/dist/primitives/use-resize-observer.d.ts +2 -2
  217. package/dist/progress-bar-jVAHvMUf.js +1 -0
  218. package/dist/prompt-suggestion-CD-qtNgC.js +1 -0
  219. package/dist/radio-BsoBMhkF.js +1 -0
  220. package/dist/react/index.d.ts +586 -19
  221. package/dist/react.js +223 -187
  222. package/dist/reasoning-4kBPtlTx.js +1 -0
  223. package/dist/register-impl-B1hLkrI8.js +424 -0
  224. package/dist/{elements/chunks/resizable-D181b4fM.js → resizable-uPmY9VY-.js} +1 -1
  225. package/dist/rotate-ccw-B2xn93py.js +1 -0
  226. package/dist/rotate-cw-CMVLoCyH.js +1 -0
  227. package/dist/schemas/form.schema.json +21 -1
  228. package/dist/schemas/tool-defs.d.ts +11 -1
  229. package/dist/schemas.js +81 -81
  230. package/dist/scroll-area-BqLUo8ZZ.js +1 -0
  231. package/dist/scroll-button-DslXiJyL.js +1 -0
  232. package/dist/select-2cLRtPGT.js +1 -0
  233. package/dist/{elements/chunks/separator-CeJHQqLW.js → separator-BWQtNJcM.js} +1 -1
  234. package/dist/{elements/chunks/settings-CqaHgJF9.js → settings-BBR63jLg.js} +1 -1
  235. package/dist/{elements/chunks/settings-group-CjqjLCOn.js → settings-group-B2ciy-Iw.js} +1 -1
  236. package/dist/{elements/chunks/skeleton-D8akBnKS.js → skeleton-CkHI-HgC.js} +1 -1
  237. package/dist/slider-DDR9U-i0.js +1 -0
  238. package/dist/{solid-BtdqNZI7.js → solid-BzCFdL25.js} +9771 -7594
  239. package/dist/{solid-CnavwBye.js → solid-DruVOXnf.js} +7893 -6183
  240. package/dist/solid.d.ts +16 -2
  241. package/dist/solid.js +256 -243
  242. package/dist/solid.server.js +256 -243
  243. package/dist/source-GEnFF528.js +1 -0
  244. package/dist/star-CilHq8GP.js +1 -0
  245. package/dist/state/index.d.ts +1 -1
  246. package/dist/state/mock.d.ts +32 -2
  247. package/dist/state.js +133 -108
  248. package/dist/store-Ciyk6eZG.js +1 -0
  249. package/dist/svelte--5p79yCD.js +1 -15
  250. package/dist/switch-KkeQIbuH.js +1 -0
  251. package/dist/tasks-card-BrN4bggJ.js +1 -0
  252. package/dist/text-shimmer-Dcj1MHuq.js +1 -0
  253. package/dist/textarea-Dpvbngbg.js +1 -0
  254. package/dist/theme.tokens.css +110 -13
  255. package/dist/{elements/chunks/thumbs-up-DX2Ijk3H.js → thumbs-up-CsT9Wzb9.js} +1 -1
  256. package/dist/toast-store-tgK6MuMv.js +1 -0
  257. package/dist/{elements/chunks/tool-DKQ2D1DP.js → tool-DzUjIBT8.js} +1 -1
  258. package/dist/{elements/chunks/tooltip-B0G99y8w.js → tooltip-Bkkg_4t0.js} +1 -1
  259. package/dist/trash-2-jBKxjGGQ.js +1 -0
  260. package/dist/{elements/chunks/triangle-alert-F9cyUEyy.js → triangle-alert-DlQ68ppf.js} +1 -1
  261. package/dist/tsx-B8rCNbgL.js +1 -6
  262. package/dist/types.d.ts +48 -3
  263. package/dist/typescript-RycA9KXf.js +1 -6
  264. package/dist/ui/checkbox-group.d.ts +83 -0
  265. package/dist/ui/checkbox.d.ts +40 -0
  266. package/dist/ui/dock.d.ts +51 -0
  267. package/dist/ui/icon.d.ts +3 -0
  268. package/dist/ui/input.d.ts +48 -2
  269. package/dist/ui/radio.d.ts +85 -0
  270. package/dist/ui/select.d.ts +71 -0
  271. package/dist/ui/slider.d.ts +65 -0
  272. package/dist/ui/switch.d.ts +9 -2
  273. package/dist/upload-TcAHXv9W.js +1 -0
  274. package/dist/url-scheme-policy-DR5DgvkM.js +1 -0
  275. package/dist/use-card-resolution-DaZqAdWf.js +1 -0
  276. package/dist/{elements/chunks/variant-aurora-qt6Zct8M.js → variant-aurora-BhLuYxJR.js} +1 -1
  277. package/dist/{variant-aurora-B8II3-I1.js → variant-aurora-CNmfHhcx.js} +2 -2
  278. package/dist/{variant-aurora-CMNWOSJR.js → variant-aurora-D6GsdTPA.js} +2 -2
  279. package/dist/{variant-aurora-CcuDMWwQ.js → variant-aurora-DbW_OWL2.js} +1 -1
  280. package/dist/{elements/chunks/variant-custom-tJp22_BQ.js → variant-custom-BRvaNHSi.js} +1 -1
  281. package/dist/{variant-custom-L16JLLZy.js → variant-custom-BvYHR62b.js} +1 -1
  282. package/dist/{variant-custom-BdvYC7af.js → variant-custom-DMTrEO5w.js} +2 -2
  283. package/dist/{variant-custom-C714mqKl.js → variant-custom-DV2x254s.js} +2 -2
  284. package/dist/{variant-wave-ecwykeyL.js → variant-wave-BNMGrDfj.js} +2 -2
  285. package/dist/{variant-wave-2S4La2Ka.js → variant-wave-BpDd8t3Z.js} +1 -1
  286. package/dist/{variant-wave-D7ruiA1W.js → variant-wave-CyBueXj9.js} +2 -2
  287. package/dist/{elements/chunks/variant-wave-CaQ5ti39.js → variant-wave-sp-qwsdI.js} +1 -1
  288. package/dist/vue-BmIZj4XD.js +1 -33
  289. package/dist/x-Z5UntkIJ.js +1 -0
  290. package/frameworks/react/index.tsx +210 -22
  291. package/llms-full.txt +1184 -22
  292. package/llms.txt +6 -3
  293. package/package.json +17 -4
  294. package/src/agent-tooling/README.md +192 -0
  295. package/src/agent-tooling/catalog/invariants.ts +3 -3
  296. package/src/agent-tooling/catalog/surfaces.ts +72 -0
  297. package/src/agent-tooling/construct/cli-entry.ts +8 -0
  298. package/src/agent-tooling/construct/cli.ts +147 -0
  299. package/src/agent-tooling/construct/codegen.ts +1635 -0
  300. package/src/agent-tooling/construct/construct.v1.schema.json +319 -0
  301. package/src/agent-tooling/construct/dev.ts +148 -0
  302. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +7 -0
  303. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +44 -0
  304. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +32 -0
  305. package/src/agent-tooling/construct/schema.ts +452 -0
  306. package/src/agent-tooling/mcp/server.ts +2 -1
  307. package/src/agent-tooling/mcp/tools/construct.ts +130 -0
  308. package/src/agent-tooling/mcp/tools/debug.ts +126 -4
  309. package/src/agent-tooling/mcp/tools/reference.ts +104 -3
  310. package/src/agent-tooling/recipes/composed-thread.ts +714 -0
  311. package/src/agent-tooling/recipes/index.ts +22 -0
  312. package/src/agent-tooling/recipes/types.ts +32 -0
  313. package/src/agent-tooling/registry.ts +5 -0
  314. package/src/components/attachment-types.ts +7 -0
  315. package/src/components/audio-visualizer/fit-scale.ts +1 -1
  316. package/src/components/card-renderer.tsx +39 -8
  317. package/src/components/card.tsx +10 -2
  318. package/src/components/chat-scope-picker.tsx +2 -2
  319. package/src/components/chat-thread.tsx +602 -43
  320. package/src/components/choice-card.tsx +102 -37
  321. package/src/components/coachmark.tsx +1 -1
  322. package/src/components/code-block.tsx +2 -2
  323. package/src/components/composer.tsx +89 -15
  324. package/src/components/confirm-card.tsx +20 -4
  325. package/src/components/conversation-item.tsx +56 -9
  326. package/src/components/conversation-list.tsx +25 -10
  327. package/src/components/conversation-panel.tsx +118 -0
  328. package/src/components/empty.tsx +14 -3
  329. package/src/components/file-tree.tsx +5 -1
  330. package/src/components/form-widgets.tsx +257 -195
  331. package/src/components/form.tsx +297 -9
  332. package/src/components/home-panel.tsx +159 -0
  333. package/src/components/loader.tsx +12 -5
  334. package/src/components/message-skills.tsx +1 -1
  335. package/src/components/message.tsx +71 -11
  336. package/src/components/prompt-input.tsx +7 -1
  337. package/src/components/prompt-suggestion.tsx +4 -1
  338. package/src/components/reasoning.tsx +30 -3
  339. package/src/components/response-compare.tsx +2 -2
  340. package/src/components/scroll-button.tsx +56 -4
  341. package/src/components/source.tsx +6 -1
  342. package/src/components/tasks-card.tsx +58 -16
  343. package/src/components/thread.tsx +10 -1
  344. package/src/components/toast.tsx +1 -1
  345. package/src/components/tool-types.ts +9 -0
  346. package/src/components/widget-tab-bar.tsx +73 -0
  347. package/src/elements/attachments.tsx +3 -1
  348. package/src/elements/chat-workspace.tsx +1 -1
  349. package/src/elements/chat.tsx +115 -5
  350. package/src/elements/checkbox-group.tsx +164 -0
  351. package/src/elements/checkbox.tsx +134 -0
  352. package/src/elements/compiled.css +1 -1
  353. package/src/elements/composer.tsx +12 -1
  354. package/src/elements/conversation-item.tsx +62 -22
  355. package/src/elements/conversation-list.tsx +2 -2
  356. package/src/elements/define-entry.ts +12 -0
  357. package/src/elements/dock.tsx +11 -0
  358. package/src/elements/element-data-types.ts +40 -0
  359. package/src/elements/element-manifest.json +24 -0
  360. package/src/elements/element-meta.json +767 -34
  361. package/src/elements/element-nonscalar.json +17 -0
  362. package/src/elements/element-types.d.ts +380 -26
  363. package/src/elements/feedback-bar.tsx +5 -0
  364. package/src/elements/icon-names.json +29 -0
  365. package/src/elements/input.tsx +312 -23
  366. package/src/elements/message.tsx +2 -0
  367. package/src/elements/pane-grid.tsx +111 -0
  368. package/src/elements/prompt-input.tsx +8 -2
  369. package/src/elements/radio-group.tsx +129 -0
  370. package/src/elements/register-impl.ts +6 -0
  371. package/src/elements/scroll-button.tsx +54 -6
  372. package/src/elements/select.tsx +165 -0
  373. package/src/elements/slider.tsx +171 -0
  374. package/src/elements/slots.ts +1 -1
  375. package/src/elements/styles.css +89 -3
  376. package/src/elements/thread.tsx +2 -0
  377. package/src/elements/toast.tsx +14 -1
  378. package/src/index.ts +5 -2
  379. package/src/primitives/card-data-types.ts +49 -0
  380. package/src/primitives/card-host.tsx +4 -2
  381. package/src/primitives/card-routing.ts +7 -56
  382. package/src/primitives/card-schemas/form.schema.json +21 -1
  383. package/src/primitives/card-validate.ts +10 -2
  384. package/src/primitives/chat-config.tsx +33 -6
  385. package/src/primitives/conversation-store.ts +248 -0
  386. package/src/primitives/field-mask.ts +256 -0
  387. package/src/primitives/field-semantics.ts +115 -0
  388. package/src/primitives/input-mask.ts +853 -0
  389. package/src/primitives/toast-store.ts +66 -4
  390. package/src/primitives/url-scheme-policy.ts +70 -0
  391. package/src/primitives/use-resize-observer.ts +2 -2
  392. package/src/schemas/tool-defs.ts +12 -2
  393. package/src/solid.ts +20 -2
  394. package/src/state/index.ts +1 -1
  395. package/src/state/mock.ts +92 -6
  396. package/src/types.ts +45 -3
  397. package/src/ui/agent-card.tsx +2 -2
  398. package/src/ui/avatar.tsx +1 -1
  399. package/src/ui/checkbox-group.tsx +153 -0
  400. package/src/ui/checkbox.tsx +63 -0
  401. package/src/ui/dock.tsx +192 -7
  402. package/src/ui/icon.tsx +53 -0
  403. package/src/ui/input.tsx +249 -9
  404. package/src/ui/kbd.tsx +1 -1
  405. package/src/ui/nav.tsx +1 -1
  406. package/src/ui/pane-group.tsx +2 -2
  407. package/src/ui/radio.tsx +150 -0
  408. package/src/ui/select.tsx +168 -0
  409. package/src/ui/slider.tsx +178 -0
  410. package/src/ui/switch.tsx +49 -18
  411. package/src/utils/cn.ts +11 -5
  412. package/theme.css +112 -13
  413. package/dist/elements/chunks/action-icons-D9u3OzYW.js +0 -1
  414. package/dist/elements/chunks/arrow-left-CVh1TeN7.js +0 -1
  415. package/dist/elements/chunks/artifact-BkYcfIlZ.js +0 -1
  416. package/dist/elements/chunks/attachments-DwfNlubq.js +0 -1
  417. package/dist/elements/chunks/badge-Q0-Cmwzz.js +0 -1
  418. package/dist/elements/chunks/bash-InADTalH.js +0 -1
  419. package/dist/elements/chunks/card-renderer-3Dyl-FpN.js +0 -1
  420. package/dist/elements/chunks/card-routing-BK09BdmL.js +0 -1
  421. package/dist/elements/chunks/check-B5kBPKeo.js +0 -1
  422. package/dist/elements/chunks/chevron-down-DZ1GS39h.js +0 -1
  423. package/dist/elements/chunks/chevron-right-CvP7OUd2.js +0 -1
  424. package/dist/elements/chunks/choice-card-D4QUIOWZ.js +0 -1
  425. package/dist/elements/chunks/circle-CDf9g6MQ.js +0 -1
  426. package/dist/elements/chunks/circle-check-CA47Nqbz.js +0 -1
  427. package/dist/elements/chunks/circle-x-CJ_HVbC8.js +0 -1
  428. package/dist/elements/chunks/code-block-BdLiTitd.js +0 -1
  429. package/dist/elements/chunks/composer-Byve-n8K.js +0 -69
  430. package/dist/elements/chunks/confirm-card-B0flE3MN.js +0 -1
  431. package/dist/elements/chunks/controllable-DTwTIlwp.js +0 -1
  432. package/dist/elements/chunks/conversation-item-BDztezOG.js +0 -1
  433. package/dist/elements/chunks/copy-Nf-kqxXH.js +0 -1
  434. package/dist/elements/chunks/core-AYMC6_lb.js +0 -12
  435. package/dist/elements/chunks/css-M7EaDHN_.js +0 -1
  436. package/dist/elements/chunks/default-input-C2iLFq0b.js +0 -1
  437. package/dist/elements/chunks/define-wjHR1MkU.js +0 -1
  438. package/dist/elements/chunks/download-C4V7tBdb.js +0 -1
  439. package/dist/elements/chunks/embed-D3KewsIJ.js +0 -1
  440. package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +0 -141
  441. package/dist/elements/chunks/file-text-D1G8khle.js +0 -1
  442. package/dist/elements/chunks/folder-WW2LGLid.js +0 -1
  443. package/dist/elements/chunks/form-CQirdC4W.js +0 -1
  444. package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +0 -1
  445. package/dist/elements/chunks/github-light-JYsPkUQd.js +0 -1
  446. package/dist/elements/chunks/hover-card-CJJkfHTK.js +0 -1
  447. package/dist/elements/chunks/html-CPZ3oZQ7.js +0 -1
  448. package/dist/elements/chunks/icon-Cfgmf4fa.js +0 -1
  449. package/dist/elements/chunks/info-DX3YMOt6.js +0 -1
  450. package/dist/elements/chunks/input-BtW9U6Sq.js +0 -1
  451. package/dist/elements/chunks/javascript-C25yR2R2.js +0 -1
  452. package/dist/elements/chunks/json-DxJze_jm.js +0 -1
  453. package/dist/elements/chunks/kbd-LGXwuT_V.js +0 -1
  454. package/dist/elements/chunks/link-2My69BqT.js +0 -1
  455. package/dist/elements/chunks/loader-iOxc_Tu-.js +0 -1
  456. package/dist/elements/chunks/message-VMZohrXx.js +0 -1
  457. package/dist/elements/chunks/message-circle-CpXMM-_n.js +0 -1
  458. package/dist/elements/chunks/message-square-DxcWtETQ.js +0 -1
  459. package/dist/elements/chunks/message-tZmV2A3p.js +0 -1
  460. package/dist/elements/chunks/paperclip-CRZVp4z_.js +0 -1
  461. package/dist/elements/chunks/progress-bar-DNy66e_E.js +0 -1
  462. package/dist/elements/chunks/prompt-suggestion-Bn64Nl7L.js +0 -1
  463. package/dist/elements/chunks/reasoning-Emn9N4-T.js +0 -1
  464. package/dist/elements/chunks/rotate-cw-CPWe37D9.js +0 -1
  465. package/dist/elements/chunks/scroll-area-ClZkZxIk.js +0 -1
  466. package/dist/elements/chunks/scroll-button-DPE-t3x_.js +0 -1
  467. package/dist/elements/chunks/share-CyfnNEqp.js +0 -1
  468. package/dist/elements/chunks/source-UWCvmVak.js +0 -1
  469. package/dist/elements/chunks/star-DoHFAikQ.js +0 -1
  470. package/dist/elements/chunks/store-Cjq0qwYN.js +0 -1
  471. package/dist/elements/chunks/svelte--5p79yCD.js +0 -1
  472. package/dist/elements/chunks/tasks-card-CmZ5xh6v.js +0 -1
  473. package/dist/elements/chunks/text-shimmer-DYn09zrz.js +0 -1
  474. package/dist/elements/chunks/textarea-skiGHURM.js +0 -1
  475. package/dist/elements/chunks/toast-store-CFnQpThX.js +0 -1
  476. package/dist/elements/chunks/tsx-B8rCNbgL.js +0 -1
  477. package/dist/elements/chunks/typescript-RycA9KXf.js +0 -1
  478. package/dist/elements/chunks/use-card-resolution-DoA2f_EU.js +0 -1
  479. package/dist/elements/chunks/vue-BmIZj4XD.js +0 -1
  480. package/dist/elements/chunks/x-B6UnOiLw.js +0 -1
  481. package/dist/llms/llms-full.txt +0 -2949
  482. package/dist/llms/llms.txt +0 -156
  483. package/dist/register-impl-DpE7icIb.js +0 -293
  484. package/dist/ui/stat.d.ts +0 -16
  485. package/src/ui/stat.tsx +0 -41
  486. /package/dist/{elements/chunks/card-tags-D8lZ-C_U.js → card-tags-D8lZ-C_U.js} +0 -0
  487. /package/dist/{elements/chunks/link-preview-DNILK391.js → link-preview-DNILK391.js} +0 -0
  488. /package/dist/{elements/chunks/slots-DaNjX0rc.js → slots-DaNjX0rc.js} +0 -0
@@ -19,7 +19,9 @@ import {
19
19
  interface Props extends Record<string, unknown> {
20
20
  /** The attachments to render. Omit (or pass an empty array) for the empty
21
21
  * state, which shows `emptyText` if set and nothing otherwise. Set as a JS
22
- * property (array). */
22
+ * property (array). Each item's `url` must be a `data:` URI or an https
23
+ * URL, never `URL.createObjectURL`: a `blob:` URL previews here but the
24
+ * wire encoders (`toOpenAIMessages`/`toAnthropicMessages`) refuse it. */
23
25
  items?: AttachmentData[];
24
26
  /** Layout: `grid` = visual tiles, `inline` = icon + label chips, `list` = rows. */
25
27
  variant?: AttachmentVariant;
@@ -75,7 +75,7 @@ interface Events {
75
75
  * (480px). Read once at upgrade. Parts: `header` · `start` · `main` · `end` ·
76
76
  * `footer` (the asides also match `::part(aside)`).
77
77
  *
78
- * **BREAKING (the 0.24 re-cast, spec 2026-08-20):** this element was a chat
78
+ * **BREAKING (0.24):** this element was a chat
79
79
  * preset; it is now a layout shell, and everything chat-shaped is gone from its
80
80
  * surface. Where each removed prop went:
81
81
  *
@@ -10,12 +10,63 @@ import type { ChatMessage } from './chat-types';
10
10
  import type { TriggerDef } from '../components/composer';
11
11
  import type { ComposerDoc } from '../primitives/composer-model';
12
12
  import type { ProseSize } from '../primitives/chat-config';
13
- import type { ModelOption } from '../types';
13
+ import type { ModelOption, HomeConfig, HomeLinkEntry } from '../types';
14
+ import type { ConversationStore } from '../primitives/conversation-store';
14
15
 
15
16
  type Props = Omit<ChatThreadProps,
16
17
  'class' | 'onValueChange' | 'onSubmit' | 'onAttachmentsChange' | 'onSuggestionClick' | 'onModelChange'
17
- | 'onMessageAction' | 'onWebSearch' | 'onVoice' | 'controllerRef' | 'cardTypes' | 'cardSchemas' | 'messages'
18
- | 'accept' | 'onAttachmentsRejected'> & Record<string, unknown> & {
18
+ | 'onMessageAction' | 'onWebSearch' | 'onVoice' | 'controllerRef' | 'cardTypes' | 'cardSchemas' | 'cardHostElement' | 'messages'
19
+ | 'accept' | 'onAttachmentsRejected'
20
+ // `conversations`/`store` are re-declared below (own doc comments, matching
21
+ // this element's own attribute/property conventions) rather than left to
22
+ // flow through `Omit`'s pass-through — same reason `messages` is excluded
23
+ // above. Left unexcluded, the intersection carries TWO declarations of the
24
+ // same property (the inherited `ChatThreadProps` one plus the re-declared
25
+ // one below) and `gen-element-api.mjs` concatenates both JSDoc comments into
26
+ // one duplicated, em-dash-laden description.
27
+ | 'conversations' | 'store'
28
+ // `home` is re-declared below for the same reason as `conversations`/`store`
29
+ // above (own element-facing doc comment rather than the ChatThread-level one
30
+ // flowing through `Omit`'s pass-through). `onHomeLink` is wired internally
31
+ // (JSX prop on `<ChatThread>` below) as a dispatched `kai-home-link` event,
32
+ // matching every other ChatThread callback on this element — same reasoning
33
+ // as `onConversationLoad` just below.
34
+ | 'home' | 'onHomeLink'
35
+ // `onConversationLoad` is wired internally (below, JSX prop on
36
+ // `<ChatThread>`) as a dispatched `kai-conversation-load` event — matching
37
+ // every other ChatThread callback on this element — rather than left as a
38
+ // settable JS property: a `JSX.Element`-shaped callback prop has no HTML-
39
+ // consumer analogue the way `store`/`messages` do, and the kai- contract's
40
+ // idiom for "this thread wants to tell you something" is already an event.
41
+ // Excluded from `Props` for the same reason `onValueChange`/`onSubmit`/etc
42
+ // are excluded above: it is not a property a consumer of `<kai-chat>` sets.
43
+ | 'onConversationLoad'
44
+ // `hostOpen`/`onUnreadChange` (unread indicators, 2026-08-26) are the SAME
45
+ // "types without forwarding" trap as `onConversationLoad` above, for the
46
+ // same reason: this facade does not read either off the host element and
47
+ // forward it onto `<ChatThread>` below. Both exist for a caller composing
48
+ // `ChatThread` directly as a Solid component with its OWN show/hide chrome
49
+ // to report through `hostOpen` and its own sibling control (a `Dock`'s
50
+ // `unread` badge) to mirror `onUnreadChange` onto — the construct engine's
51
+ // emitted App is the motivating case (codegen.ts's `emitChatThreadUnreadProps`),
52
+ // exactly like `headerEndContent`/`emptyContent` below. `<kai-chat>` has no
53
+ // such sibling chrome of its own to report to or read from, so there is
54
+ // nothing here for either prop to DO — left unexcluded, `gen-element-api.mjs`
55
+ // would still type them into the public API and docs as settable properties
56
+ // that silently do nothing when set.
57
+ | 'hostOpen' | 'onUnreadChange'
58
+ // `headerEndContent`/`emptyContent` are JSX.Element escape hatches for a caller
59
+ // composing `ChatThread` directly as a Solid component (see their doc comments in
60
+ // chat-thread.tsx — the construct-engine's emitted App is the motivating case).
61
+ // `<kai-chat>` is the OPPOSITE shape: a custom element crossing the shadow-DOM
62
+ // boundary, where a `JSX.Element` value cannot exist for a consumer to construct
63
+ // (React/Vue/plain HTML have no such type) and the facade already has its own
64
+ // working mechanism for both regions — `slot="header-end"` and `slot="empty"`.
65
+ // Omitted here rather than left to flow through `Omit`'s default pass-through:
66
+ // without this, `gen-element-api.mjs` picked them up and put a JSX.Element type
67
+ // (which it stringifies as Solid's internal array-like union — meaningless to a
68
+ // web-component consumer) into `<kai-chat>`'s public prop surface and docs.
69
+ | 'headerEndContent' | 'emptyContent'> & Record<string, unknown> & {
19
70
  /** Which attachment media types the user may stage, in HTML `accept` syntax:
20
71
  * `<kai-chat accept="image/*,application/pdf">`. A plain string, so unlike
21
72
  * `messages` it DOES work as an attribute. Omitted means no filter.
@@ -63,6 +114,40 @@ type Props = Omit<ChatThreadProps,
63
114
  * authored one carries `$schema`/`title`/`description`/`additionalProperties`,
64
115
  * so the tighter type would reject both of the normal ways to supply one. */
65
116
  cardSchemas?: Record<string, object>;
117
+ /** Turns on the prior-conversations list (a list-toggle button in the
118
+ * header, plus a second list view sharing the panel, C-1). Attribute-
119
+ * settable like every other boolean flag on this element:
120
+ * `<kai-chat conversations>`. Requires `store`. A row select, "new
121
+ * conversation," or the visitor's mount-time auto-restore all deliver
122
+ * their messages the same way: listen for `kai-conversation-load` and
123
+ * set `el.messages` from `event.detail.messages` (a fresh array): this
124
+ * element does not update `messages` for you. Set with no `store`, the
125
+ * underlying `ChatThread` decides loudly (one console.error) and stays
126
+ * visually off; this facade always supplies its own internal load
127
+ * handler (the `kai-conversation-load` dispatch below), so the second
128
+ * ChatThread guard, missing `onConversationLoad`, never trips here,
129
+ * even for a consumer who never listens for the event. Default false. */
130
+ conversations?: boolean;
131
+ /** The adapter this thread persists conversations through: an object of
132
+ * three functions (`list`/`load`/`save`; `ConversationStore`, exported
133
+ * from `@kitn.ai/ui`'s `primitives/conversation-store`). A JS PROPERTY
134
+ * ONLY: `el.store = myAdapter`. It can never be an attribute, since a
135
+ * function-bearing object has no HTML string form, the same reasoning
136
+ * that keeps `messages`/`cardSchemas` property-only (the kai- contract:
137
+ * array/object props are JS properties, never attributes). Two built-ins
138
+ * ship: `localStorageStore(name, userId?)` and `fetchStore(url, userId?)`. */
139
+ store?: ConversationStore;
140
+ /** Turns on the widget home screen (Intercom-pattern): the panel boots into
141
+ * a `home` view, with a greeting, most-recent-conversation card, a "new
142
+ * conversation" CTA, and host-defined links, plus a Home/Messages tab bar
143
+ * for switching back to the thread. An OBJECT, so it is a JS property only:
144
+ * `el.home = { greeting: { title: 'Hey' }, links: [...] }`, never an
145
+ * attribute (the kai- contract: array/object props are JS properties).
146
+ * A `links` entry with no `href` fires `kai-home-link` with that entry when
147
+ * tapped, rather than navigating; one WITH `href` opens it directly
148
+ * (only when the URL passes the kit's own scheme allowlist). Omit for the
149
+ * no-home widget (chat view only, unchanged). */
150
+ home?: HomeConfig;
66
151
  };
67
152
 
68
153
  interface Events {
@@ -90,6 +175,19 @@ interface Events {
90
175
  'kai-web-search': Record<string, never>;
91
176
  /** The Mic / voice button was clicked. */
92
177
  'kai-voice': Record<string, never>;
178
+ /** A conversation's history loaded: a row tap in the list, "new
179
+ * conversation," or the visitor's own mount-time auto-restore of their
180
+ * most recent thread (only fires when `conversations` is on and a `store`
181
+ * is set). `detail.id` is that conversation's id, `undefined` for the
182
+ * "new conversation" case (no id exists until the first message mints
183
+ * one, C-6). Set `el.messages = event.detail.messages` (already a fresh
184
+ * array) to actually render it, since this element does not do that for
185
+ * you; `messages` stays your own state like everywhere else on this
186
+ * element. */
187
+ 'kai-conversation-load': { id: string | undefined; messages: ChatMessage[] };
188
+ /** A `home.links` entry with no `href` was activated (tapped/clicked/Enter).
189
+ * Meaningful only when `home` is set. */
190
+ 'kai-home-link': { entry: HomeLinkEntry };
93
191
  }
94
192
 
95
193
  defineWebComponent<Props, Events>('kai-chat', {
@@ -97,8 +195,10 @@ defineWebComponent<Props, Events>('kai-chat', {
97
195
  suggestions: undefined, suggestionMode: 'submit', persistSuggestions: false, proseSize: 'sm',
98
196
  codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
99
197
  models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
100
- webSearch: false, voice: false, triggers: undefined, kindIcons: undefined,
198
+ attach: true, webSearch: false, voice: false, triggers: undefined, kindIcons: undefined,
101
199
  actionsReveal: 'always', cardTypes: undefined, cardSchemas: undefined, accept: undefined,
200
+ reasoning: undefined, reasoningOpen: undefined, conversations: false, store: undefined,
201
+ home: undefined,
102
202
  }, (props, { dispatch, flag, reflectFlag, element, expose }) => {
103
203
  // `messages` is an untyped boundary: a consumer can hand it anything at
104
204
  // runtime (a pre-0.20.0 `{ id, role, content }` array, in particular). Skip
@@ -164,12 +264,22 @@ defineWebComponent<Props, Events>('kai-chat', {
164
264
  codeTheme={props.codeTheme as string} codeHighlight={flag('codeHighlight')}
165
265
  chatTitle={props.chatTitle as string | undefined} models={props.models as ModelOption[] | undefined}
166
266
  currentModel={props.currentModel as string | undefined} context={props.context as ChatThreadContextUsage | undefined}
167
- scrollButton={props.scrollButton !== false} webSearch={flag('webSearch')} voice={flag('voice')}
267
+ scrollButton={props.scrollButton !== false} attach={flag('attach')} webSearch={flag('webSearch')} voice={flag('voice')}
268
+ reasoning={props.reasoning as 'full' | 'compact' | 'off' | undefined}
269
+ reasoningOpen={flag('reasoningOpen')}
168
270
  triggers={props.triggers as TriggerDef[] | undefined}
169
271
  kindIcons={props.kindIcons as Record<string, string> | undefined}
170
272
  actionsReveal={props.actionsReveal as 'always' | 'hover'}
171
273
  cardTypes={cardComponentsFromTags(props.cardTypes as Record<string, string> | undefined, (props as { theme?: string }).theme)}
172
274
  cardSchemas={props.cardSchemas as Record<string, object> | undefined}
275
+ conversations={flag('conversations')}
276
+ store={props.store as ConversationStore | undefined}
277
+ onConversationLoad={(messages, id) => dispatch('kai-conversation-load', { id, messages })}
278
+ home={props.home as HomeConfig | undefined}
279
+ onHomeLink={(entry) => dispatch('kai-home-link', { entry })}
280
+ /* F-26: card parts emit off THIS element as the bubbling `kai-card` event,
281
+ so `listenForCardEvents(el)` / addEventListener('kai-card') work. */
282
+ cardHostElement={element}
173
283
  onValueChange={(value) => dispatch('kai-value-change', { value })}
174
284
  onSubmit={(detail) => dispatch('kai-submit', detail)}
175
285
  accept={props.accept as string | undefined}
@@ -0,0 +1,164 @@
1
+ import { createEffect, createSignal, untrack } from 'solid-js';
2
+ import { defineWebComponent } from './define';
3
+ import { CheckboxGroup } from '../ui/checkbox-group';
4
+ // Public shape of the `options` prop; lives in ./element-data-types so the ROOT
5
+ // entry can re-export it (see that file's header).
6
+ import type { KaiCheckboxOption } from './element-data-types';
7
+
8
+ interface Props extends Record<string, unknown> {
9
+ /** The choices, top to bottom. Set as a JS PROPERTY (array), never an attribute.
10
+ * Rendered in full: the kit never truncates, re-orders or de-duplicates them. */
11
+ options: KaiCheckboxOption[];
12
+ /** The FIRST selected value. Settable and reflected to the `value` attribute, so
13
+ * `:host([value])` and `el.value` see live state, and a seed can be written in
14
+ * markup. Writing it makes that the whole selection; to read or drive the rest,
15
+ * use `el.values`. */
16
+ value?: string;
17
+ /**
18
+ * The shared form-control name every box carries, so `FormData.getAll(name)` reads
19
+ * the whole selection back under one key.
20
+ *
21
+ * NO DEFAULT, unlike `<kai-radio-group>`. A radio set needs a shared `name` for the
22
+ * browser to make it exclusive and arrow-navigable, so one is generated when none is
23
+ * given; checkboxes are independent controls and behave correctly with no name at
24
+ * all. Generating one here would submit the selection under a random key, which is
25
+ * worse than submitting nothing.
26
+ *
27
+ * The element is NOT form-associated (no `ElementInternals`, no `setFormValue()`),
28
+ * the same known gap `<kai-input>` records: the boxes live in a shadow root, so a
29
+ * surrounding `<form>` collects nothing from them whether or not `name` is set. Read
30
+ * `el.values`. The name still lands on every inner input, so it is right the day form
31
+ * association arrives.
32
+ */
33
+ name?: string;
34
+ /** Disable every row. Individual rows carry their own `disabled`. */
35
+ disabled?: boolean;
36
+ /** Accessible name for the group. */
37
+ label?: string;
38
+ }
39
+
40
+ /** Events fired by `<kai-checkbox-group>`. */
41
+ interface Events {
42
+ /** A row was ticked or unticked. `values` is the whole selection after the change,
43
+ * which is what a multi-select control needs; `value` is the first of them (empty
44
+ * when nothing is selected). Both are always present, so neither shape silently
45
+ * loses the other. This is `<kai-select>`'s detail, deliberately. */
46
+ 'kai-change': { value: string; values: string[] };
47
+ }
48
+
49
+ /**
50
+ * `<kai-checkbox-group>` — the kit's "pick any number" control, and
51
+ * `<kai-radio-group>`'s sibling: the same options shape and the same divided row
52
+ * chrome over real `<input type="checkbox">`es, multi-value instead of exclusive. A
53
+ * box per tab stop, Space to toggle and correct announcement are the browser's, not a
54
+ * reimplementation.
55
+ *
56
+ * Feed it `options` (a JS-property array of `{ value, label, description?, disabled? }`),
57
+ * drive and read the selection with the `values` property, and listen for `kai-change`.
58
+ * `value` is the first selected option and is reflected to the `value` attribute.
59
+ *
60
+ * Re-rendering follows the kit's reactivity contract: hand it a NEW array reference,
61
+ * and a new object for any option whose content changed — the rows are a
62
+ * reference-keyed list, so mutating an option in place changes nothing on screen.
63
+ *
64
+ * No validation and no limits: "at least one", "at most three" and anything else that
65
+ * lands in a policy document is the application's rule, not the kit's.
66
+ *
67
+ * ```html
68
+ * <kai-checkbox-group label="Environments" name="env"></kai-checkbox-group>
69
+ * <script type="module">
70
+ * import '@kitn.ai/ui/elements';
71
+ * const group = document.querySelector('kai-checkbox-group');
72
+ * // ARRAY prop — a JS property, never an attribute.
73
+ * group.options = [
74
+ * { value: 'prod', label: 'Production', description: 'Pages the on-call' },
75
+ * { value: 'staging', label: 'Staging' },
76
+ * { value: 'dev', label: 'Development' },
77
+ * ];
78
+ * group.addEventListener('kai-change', (e) => console.log(e.detail.values));
79
+ * group.values = ['prod', 'dev']; // drive it (no kai-change — the host already knows)
80
+ * </script>
81
+ * ```
82
+ */
83
+ defineWebComponent<Props, Events>('kai-checkbox-group', {
84
+ options: [],
85
+ value: undefined,
86
+ name: undefined,
87
+ disabled: undefined,
88
+ label: undefined,
89
+ }, (props, ctx) => {
90
+ const { element, dispatch, flag, expose } = ctx;
91
+
92
+ // Lift the selection into the facade and drive CheckboxGroup CONTROLLED so the host
93
+ // can read it (`el.values` / `:host([value])`) and set it after mount. Seed from the
94
+ // `value` property/attribute present on mount; nothing is auto-selected, because
95
+ // `options` normally arrives as a property AFTER upgrade (kai-select's structure).
96
+ const seed = (props.value as string | undefined) ?? element.getAttribute('value') ?? '';
97
+ const [values, setValues] = createSignal<string[]>(seed ? [seed] : []);
98
+ const first = () => values()[0] ?? '';
99
+
100
+ // Coerce anything arriving through the `value` setter (a JS assignment, or the
101
+ // attributeChangedCallback write-back the reflect effect below triggers) to a string,
102
+ // falling back to the live attribute when nullish so the write-back equals the signal
103
+ // and the guard absorbs it — no attr⇄prop feedback loop.
104
+ const coerce = (v: unknown): string =>
105
+ v == null ? (element.getAttribute('value') ?? '') : String(v);
106
+
107
+ // Apply a new selection and fire kai-change once (the user-toggle path).
108
+ const apply = (next: string[]) => {
109
+ const prev = untrack(values);
110
+ if (prev.length === next.length && prev.every((v, i) => v === next[i])) return;
111
+ setValues(next);
112
+ dispatch('kai-change', { value: next[0] ?? '', values: next });
113
+ };
114
+
115
+ Object.defineProperty(element, 'value', {
116
+ get: () => first(),
117
+ set: (v: unknown) => {
118
+ const next = coerce(v);
119
+ if (untrack(first) !== next) setValues(next ? [next] : []);
120
+ },
121
+ configurable: true,
122
+ enumerable: true,
123
+ });
124
+
125
+ // The multi-selection read/write side, spelled exactly as `<kai-select multiple>`
126
+ // spells it. `value` alone cannot represent a checkbox group's selection, and
127
+ // returning only the first ticked box would be a silent drop.
128
+ Object.defineProperty(element, 'values', {
129
+ get: () => values(),
130
+ set: (v: unknown) => setValues(Array.isArray(v) ? v.map(String) : []),
131
+ configurable: true,
132
+ enumerable: true,
133
+ });
134
+
135
+ // Reflect the first value → the `[value]` host attribute (for `:host([value])`).
136
+ createEffect(() => {
137
+ const v = first();
138
+ if (v) {
139
+ if (element.getAttribute('value') !== v) element.setAttribute('value', v);
140
+ } else if (element.hasAttribute('value')) {
141
+ element.removeAttribute('value');
142
+ }
143
+ });
144
+
145
+ expose({
146
+ /** Focus the group's first box. Not "the first ticked one", which is
147
+ * `<kai-radio-group>`'s rule: a radio group is ONE tab stop that lands on the
148
+ * selection, while every checkbox here is its own tab stop, so the entry point is
149
+ * simply the top of the list. */
150
+ focus: (options?: FocusOptions) =>
151
+ element.shadowRoot?.querySelector<HTMLInputElement>('input[type="checkbox"]')?.focus(options),
152
+ });
153
+
154
+ return (
155
+ <CheckboxGroup
156
+ options={(props.options ?? []) as KaiCheckboxOption[]}
157
+ value={values()}
158
+ name={props.name as string | undefined}
159
+ disabled={flag('disabled')}
160
+ label={props.label as string | undefined}
161
+ onChange={(next) => apply(next)}
162
+ />
163
+ );
164
+ });
@@ -0,0 +1,134 @@
1
+ import { createEffect, createSignal, untrack } from 'solid-js';
2
+ import { defineWebComponent } from './define';
3
+ import { Checkbox } from '../ui/checkbox';
4
+
5
+ interface Props extends Record<string, unknown> {
6
+ /** Controlled checked state. Settable and reflected to the `checked` attribute.
7
+ * `el.checked = true` (or `<kai-checkbox checked>`) drives it; ticking the box
8
+ * updates it and fires `kai-change`. Read `el.checked` for live state. */
9
+ checked?: boolean;
10
+ /** Initial checked state on mount (uncontrolled seed). Bare attribute
11
+ * (`<kai-checkbox default-checked>`) turns it on. */
12
+ defaultChecked?: boolean;
13
+ /** The mixed state, for a parent box whose children are partly ticked. Visual
14
+ * plus an accessibility hint: the box still reports `checked === false`. */
15
+ indeterminate?: boolean;
16
+ /** Disable interaction. */
17
+ disabled?: boolean;
18
+ /** Set the native `required` attribute, and nothing more. Whether an unticked box
19
+ * is an error is the application's rule, not the kit's. */
20
+ required?: boolean;
21
+ /** Accessible label. The visible text beside the box is the consumer's to render. */
22
+ label?: string;
23
+ /** Form-control name (paired with `value`). */
24
+ name?: string;
25
+ /** Submitted value when checked (paired with `name`). Defaults to `'on'`. */
26
+ value?: string;
27
+ }
28
+
29
+ /** Events fired by `<kai-checkbox>`. */
30
+ interface Events {
31
+ /** The box was ticked or unticked. */
32
+ 'kai-change': { checked: boolean };
33
+ }
34
+
35
+ /**
36
+ * `<kai-checkbox>` — a checkbox over a real `<input type="checkbox">`. Drive/read
37
+ * its state with the `checked` property (settable + reflected to the `checked`
38
+ * attribute, so `:host([checked])` and `el.checked` see live state); seed the
39
+ * initial state with `default-checked` and read changes from `kai-change`.
40
+ *
41
+ * ```html
42
+ * <label>
43
+ * <kai-checkbox default-checked label="Stream responses"></kai-checkbox>
44
+ * Stream responses
45
+ * </label>
46
+ * <script type="module">
47
+ * import '@kitn.ai/ui/elements';
48
+ * const box = document.querySelector('kai-checkbox');
49
+ * box.addEventListener('kai-change', (e) => console.log(e.detail.checked));
50
+ * box.checked = false; // drive it (no kai-change — the host already knows)
51
+ * box.indeterminate = true;
52
+ * box.toggle(); // flip it (fires kai-change)
53
+ * </script>
54
+ * ```
55
+ */
56
+ defineWebComponent<Props, Events>('kai-checkbox', {
57
+ checked: undefined,
58
+ defaultChecked: undefined,
59
+ indeterminate: undefined,
60
+ disabled: undefined,
61
+ required: undefined,
62
+ label: undefined,
63
+ name: undefined,
64
+ value: undefined,
65
+ }, (props, ctx) => {
66
+ const { element, dispatch, flag, expose } = ctx;
67
+
68
+ // Lift the on/off state into the facade and drive Checkbox CONTROLLED so the host
69
+ // can read it (`el.checked` / `:host([checked])`) and set it after mount. Seed from
70
+ // `defaultChecked` (or a bare `checked` attribute present on mount). This is
71
+ // kai-switch's structure, deliberately — same contract, same failure modes.
72
+ const [checked, setChecked] = createSignal(flag('defaultChecked') || flag('checked'));
73
+
74
+ // Coerce anything arriving through the `checked` setter (a JS assignment, or the
75
+ // write-back `attributeChangedCallback` fires when the attribute changes) to a
76
+ // boolean, falling back to attribute presence to match `flag`'s semantics. The
77
+ // `undefined` write-back `toggleAttribute` triggers thus resolves to the attribute
78
+ // just written, equals the signal, and is absorbed by the guard below — no attr⇄prop
79
+ // feedback loop.
80
+ const coerce = (v: unknown): boolean =>
81
+ v === true ? true
82
+ : v === false ? false
83
+ : element.hasAttribute('checked') && element.getAttribute('checked') !== 'false';
84
+
85
+ // Apply a new checked state and fire kai-change once (the user path). No-op while
86
+ // disabled.
87
+ const apply = (next: boolean) => {
88
+ if (flag('disabled')) return;
89
+ if (untrack(checked) === next) return;
90
+ setChecked(next);
91
+ dispatch('kai-change', { checked: next });
92
+ };
93
+
94
+ // Reads return LIVE state; host writes drive it WITHOUT firing kai-change — the
95
+ // host already knows what it set. The equality guard kills the reflect write-back.
96
+ Object.defineProperty(element, 'checked', {
97
+ get: () => checked(),
98
+ set: (v: unknown) => { const next = coerce(v); if (untrack(checked) !== next) setChecked(next); },
99
+ configurable: true,
100
+ enumerable: true,
101
+ });
102
+
103
+ // Reflect internal checked → the `[checked]` host attribute (for `:host([checked])`).
104
+ createEffect(() => {
105
+ const c = checked();
106
+ if (c !== element.hasAttribute('checked')) element.toggleAttribute('checked', c);
107
+ });
108
+
109
+ expose({
110
+ /** Flip the box and fire `kai-change` (no-op while disabled). */
111
+ toggle: () => apply(!untrack(checked)),
112
+ /** Focus the inner input (the host element can't reach it). */
113
+ focus: (options?: FocusOptions) =>
114
+ element.shadowRoot?.querySelector<HTMLInputElement>('input[type="checkbox"]')?.focus(options),
115
+ });
116
+
117
+ return (
118
+ <>
119
+ {/* Base sets `:host{display:block}`; a checkbox flows inline beside its text. */}
120
+ <style>{':host{display:inline-flex}'}</style>
121
+ <Checkbox
122
+ checked={checked()}
123
+ indeterminate={flag('indeterminate')}
124
+ disabled={flag('disabled')}
125
+ required={flag('required')}
126
+ aria-label={props.label as string | undefined}
127
+ aria-checked={flag('indeterminate') ? 'mixed' : undefined}
128
+ name={props.name as string | undefined}
129
+ value={(props.value as string | undefined) ?? 'on'}
130
+ onChange={(e) => apply(e.currentTarget.checked)}
131
+ />
132
+ </>
133
+ );
134
+ });