@kitn.ai/ui 0.26.0 → 0.27.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 (474) hide show
  1. package/README.md +16 -5
  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-BnFKqqtY.js} +1 -1
  6. package/dist/action-icons-CBskfBMz.js +1 -0
  7. package/dist/arrow-down-Br0qtpsz.js +1 -0
  8. package/dist/arrow-left-Dj7xgE12.js +1 -0
  9. package/dist/artifact-CvXEm1lS.js +1 -0
  10. package/dist/assets/dev-5XzXYR21.js +91 -0
  11. package/dist/attachments-C43ZegEq.js +1 -0
  12. package/dist/{elements/chunks/audio-visualizer-D7lB6mvR.js → audio-visualizer-B-79y1Tj.js} +1 -1
  13. package/dist/badge-BpUbq8c0.js +1 -0
  14. package/dist/bash-InADTalH.js +1 -6
  15. package/dist/bell-sn17Ip9v.js +1 -0
  16. package/dist/{elements/chunks/button-flUbeufF.js → button-BH6rN0U-.js} +1 -1
  17. package/dist/card-renderer-Cb1gQmth.js +1 -0
  18. package/dist/card-routing-DifQgS7n.js +1 -0
  19. package/dist/check-DPeeMUYx.js +1 -0
  20. package/dist/checkbox-Dc9Yov_B.js +1 -0
  21. package/dist/checkbox-group-B1kDLLYk.js +1 -0
  22. package/dist/chevron-down-CHSWk7ZT.js +1 -0
  23. package/dist/chevron-right-B7l_fMgx.js +1 -0
  24. package/dist/choice-card-BT3c1S8g.js +1 -0
  25. package/dist/circle-Bb0yOpqM.js +1 -0
  26. package/dist/circle-check-BGZpCiz7.js +1 -0
  27. package/dist/circle-x-wobWkoSx.js +1 -0
  28. package/dist/{elements/chunks/cn-CU7UAWzk.js → cn-DN5AWfiS.js} +1 -1
  29. package/dist/{elements/chunks/code-block-BdLiTitd.js → code-block-CUQ5mtv0.js} +1 -1
  30. package/dist/{elements/chunks/collapsible-BzbXpPzr.js → collapsible-CPJbf6FM.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 +46 -1
  36. package/dist/components/conversation-item.d.ts +19 -7
  37. package/dist/components/conversation-list.d.ts +17 -5
  38. package/dist/components/form-widgets.d.ts +67 -2
  39. package/dist/components/form.d.ts +48 -1
  40. package/dist/components/message.d.ts +25 -3
  41. package/dist/components/reasoning.d.ts +6 -0
  42. package/dist/components/scroll-button.d.ts +11 -0
  43. package/dist/components/thread.d.ts +5 -0
  44. package/dist/components/tool-types.d.ts +9 -0
  45. package/dist/composer-CjngLzal.js +106 -0
  46. package/dist/confirm-card-DCx_A4bU.js +1 -0
  47. package/dist/construct-cli.es.js +1169 -0
  48. package/dist/{elements/chunks/context-VLIL3sJ-.js → context-BY8V-Nlp.js} +1 -1
  49. package/dist/controllable-D43BKmtX.js +1 -0
  50. package/dist/conversation-list-D4lLU_yS.js +1 -0
  51. package/dist/copy-B6DO4PqB.js +1 -0
  52. package/dist/core-AYMC6_lb.js +12 -5874
  53. package/dist/{create-tween-CQED4T0g.js → create-tween-BPzaefTp.js} +1 -1
  54. package/dist/{create-tween-BFT6c-Y8.js → create-tween-CnMHviKB.js} +1 -1
  55. package/dist/{create-tween-CJNlzoaO.js → create-tween-D1aiGZZh.js} +1 -1
  56. package/dist/{elements/chunks/create-tween-c4Z8TDYz.js → create-tween-DUSQUKpr.js} +2 -2
  57. package/dist/css-M7EaDHN_.js +1 -6
  58. package/dist/custom-elements.json +1400 -218
  59. package/dist/default-input-CucQEOqH.js +1 -0
  60. package/dist/define-CGGX-7Vg.js +1 -0
  61. package/dist/define.d.ts +4 -0
  62. package/dist/define.js +510 -0
  63. package/dist/define.server.d.ts +5 -0
  64. package/dist/define.server.js +506 -0
  65. package/dist/{elements/chunks/disclosure-CcNbyLy0.js → disclosure-CbLtajUQ.js} +1 -1
  66. package/dist/{elements/chunks/dropdown-BgWTthUx.js → dropdown-BwhViJFd.js} +1 -1
  67. package/dist/elements/agent-card.js +1 -1
  68. package/dist/elements/artifact.js +1 -1
  69. package/dist/elements/attachments.js +1 -1
  70. package/dist/elements/audio-visualizer.js +1 -1
  71. package/dist/elements/autoloader.js +1 -1
  72. package/dist/elements/avatar.js +1 -1
  73. package/dist/elements/badge.js +1 -1
  74. package/dist/elements/button.js +1 -1
  75. package/dist/elements/card.js +1 -1
  76. package/dist/elements/cards.js +1 -1
  77. package/dist/elements/chain-of-thought.js +1 -1
  78. package/dist/elements/chat-scope-picker.js +1 -1
  79. package/dist/elements/chat-workspace.js +1 -1
  80. package/dist/elements/chat.js +1 -1
  81. package/dist/elements/checkbox-group.d.ts +1 -0
  82. package/dist/elements/checkbox-group.js +1 -0
  83. package/dist/elements/checkbox.d.ts +1 -0
  84. package/dist/elements/checkbox.js +1 -0
  85. package/dist/elements/checkpoint.js +1 -1
  86. package/dist/elements/choice.js +1 -1
  87. package/dist/elements/coachmark.js +1 -1
  88. package/dist/elements/code-block.js +1 -1
  89. package/dist/elements/command.js +1 -1
  90. package/dist/elements/compare.js +1 -1
  91. package/dist/elements/composer.js +1 -1
  92. package/dist/elements/confirm-card.js +1 -1
  93. package/dist/elements/context-meter.js +1 -1
  94. package/dist/elements/conversation-item.js +1 -1
  95. package/dist/elements/conversation-list.js +1 -1
  96. package/dist/elements/define-entry.d.ts +12 -0
  97. package/dist/elements/dialog.js +1 -1
  98. package/dist/elements/dock.js +101 -7
  99. package/dist/elements/dropdown.js +1 -1
  100. package/dist/elements/editable-label.js +1 -1
  101. package/dist/elements/element-data-types.d.ts +37 -0
  102. package/dist/elements/embed.js +1 -1
  103. package/dist/elements/empty.js +1 -1
  104. package/dist/elements/feedback-bar.js +1 -1
  105. package/dist/elements/file-tree.js +1 -1
  106. package/dist/elements/file-upload.js +1 -1
  107. package/dist/elements/form.js +1 -1
  108. package/dist/elements/hover-card.js +1 -1
  109. package/dist/elements/icon.js +1 -1
  110. package/dist/elements/image.js +1 -1
  111. package/dist/elements/input.js +1 -1
  112. package/dist/elements/kbd.js +1 -1
  113. package/dist/elements/link-preview.js +1 -1
  114. package/dist/elements/loader.js +1 -1
  115. package/dist/elements/markdown.js +1 -1
  116. package/dist/elements/menu.js +1 -1
  117. package/dist/elements/message-skills.js +1 -1
  118. package/dist/elements/message.js +1 -1
  119. package/dist/elements/model-switcher.js +1 -1
  120. package/dist/elements/nav.js +1 -1
  121. package/dist/elements/notice.js +1 -1
  122. package/dist/elements/pane-grid.d.ts +1 -0
  123. package/dist/elements/pane-grid.js +1 -0
  124. package/dist/elements/pane-group.js +1 -1
  125. package/dist/elements/pane.js +1 -1
  126. package/dist/elements/popover.js +1 -1
  127. package/dist/elements/progress-bar.js +1 -1
  128. package/dist/elements/prompt-dock.js +1 -1
  129. package/dist/elements/prompt-input.js +1 -1
  130. package/dist/elements/prompt-suggestions.js +1 -1
  131. package/dist/elements/radio-group.d.ts +1 -0
  132. package/dist/elements/radio-group.js +1 -0
  133. package/dist/elements/reasoning.js +1 -1
  134. package/dist/elements/remote.js +1 -1
  135. package/dist/elements/resizable.js +1 -1
  136. package/dist/elements/response-stream.js +2 -2
  137. package/dist/elements/screen.js +1 -1
  138. package/dist/elements/scroll-area.js +1 -1
  139. package/dist/elements/scroll-button.js +1 -1
  140. package/dist/elements/search.js +1 -1
  141. package/dist/elements/segmented.js +1 -1
  142. package/dist/elements/select.d.ts +1 -0
  143. package/dist/elements/select.js +1 -0
  144. package/dist/elements/separator.js +1 -1
  145. package/dist/elements/setting-item.js +1 -1
  146. package/dist/elements/settings-group.js +1 -1
  147. package/dist/elements/skeleton.js +1 -1
  148. package/dist/elements/slider.d.ts +1 -0
  149. package/dist/elements/slider.js +1 -0
  150. package/dist/elements/slots.d.ts +1 -1
  151. package/dist/elements/source.js +1 -1
  152. package/dist/elements/status.js +1 -1
  153. package/dist/elements/switch.js +1 -1
  154. package/dist/elements/tabs.js +1 -1
  155. package/dist/elements/tasks.js +1 -1
  156. package/dist/elements/text-shimmer.js +1 -1
  157. package/dist/elements/thinking-bar.js +1 -1
  158. package/dist/elements/thread.js +1 -1
  159. package/dist/elements/toast.js +1 -1
  160. package/dist/elements/tool.js +1 -1
  161. package/dist/elements/tooltip.js +1 -1
  162. package/dist/elements/voice-input.js +1 -1
  163. package/dist/elements/voice-output.js +1 -1
  164. package/dist/elements.d.ts +362 -24
  165. package/dist/{elements/chunks/ellipsis-7gU33mL2.js → ellipsis-DFr4Vqr3.js} +1 -1
  166. package/dist/embed-5s_vU4J0.js +1 -0
  167. package/dist/engine-javascript-vq0WuIJl.js +14 -2516
  168. package/dist/{elements/chunks/external-link-CSOEsNlx.js → external-link-u9d85ORQ.js} +1 -1
  169. package/dist/file-text-CX7_x42o.js +1 -0
  170. package/dist/{elements/chunks/file-tree-zvB2i7P9.js → file-tree-D3kBjXI5.js} +1 -1
  171. package/dist/folder-V-YdIL8f.js +1 -0
  172. package/dist/form-BRNUMCN2.js +1 -0
  173. package/dist/github-dark-dimmed-DUshB20C.js +1 -4
  174. package/dist/github-light-JYsPkUQd.js +1 -4
  175. package/dist/hover-card-DaeiYrTA.js +1 -0
  176. package/dist/html-CPZ3oZQ7.js +1 -10
  177. package/dist/icon-BpixdZNq.js +1 -0
  178. package/dist/{elements/chunks/index-BCRhi84a.js → index-xu_pdcPi.js} +1 -1
  179. package/dist/index.d.ts +1 -1
  180. package/dist/index.js +7330 -5852
  181. package/dist/index.server.js +5823 -4759
  182. package/dist/info-8mFsIjS3.js +1 -0
  183. package/dist/input-d1Yuu-hz.js +1 -0
  184. package/dist/javascript-C25yR2R2.js +1 -6
  185. package/dist/json-DxJze_jm.js +1 -6
  186. package/dist/kai.es.js +1 -1
  187. package/dist/kbd-961zMPFB.js +1 -0
  188. package/dist/link-DlZZBGaR.js +1 -0
  189. package/dist/{elements/chunks/link-preview-OQ9IEq0f.js → link-preview-DIIbV2Sd.js} +1 -1
  190. package/dist/loader-YQszHFaW.js +1 -0
  191. package/dist/{elements/chunks/markdown-DgBFaGAz.js → markdown-CVk1MPsj.js} +1 -1
  192. package/dist/mcp.es.js +1285 -79
  193. package/dist/message-CwKVEdZg.js +1 -0
  194. package/dist/message-DS8lzHc1.js +1 -0
  195. package/dist/message-circle-Xf8Q-vZp.js +1 -0
  196. package/dist/message-square-Cxnwgkns.js +1 -0
  197. package/dist/{elements/chunks/minimize-2-DPIUKTrT.js → minimize-2-UEZmP2QT.js} +1 -1
  198. package/dist/{elements/chunks/model-switcher-DsT8tFB0.js → model-switcher-Kk1jEQ5t.js} +1 -1
  199. package/dist/{elements/chunks/overlay-DuiwdXjm.js → overlay-C1od6LOz.js} +1 -1
  200. package/dist/panel-right-ryET0yyn.js +1 -0
  201. package/dist/paperclip-BDNoZFJP.js +1 -0
  202. package/dist/play-OFIvYXUQ.js +1 -0
  203. package/dist/primitives/card-data-types.d.ts +49 -0
  204. package/dist/primitives/card-routing.d.ts +1 -33
  205. package/dist/primitives/card-validate.d.ts +2 -2
  206. package/dist/primitives/chat-config.d.ts +29 -2
  207. package/dist/primitives/field-mask.d.ts +96 -0
  208. package/dist/primitives/field-semantics.d.ts +36 -0
  209. package/dist/primitives/input-mask.d.ts +46 -0
  210. package/dist/primitives/url-scheme-policy.d.ts +34 -0
  211. package/dist/primitives/use-resize-observer.d.ts +2 -2
  212. package/dist/progress-bar-BvYX0aoy.js +1 -0
  213. package/dist/prompt-suggestion-BRFu2lcu.js +1 -0
  214. package/dist/radio-DcL23cNJ.js +1 -0
  215. package/dist/react/index.d.ts +193 -19
  216. package/dist/react.js +216 -180
  217. package/dist/reasoning-Cackq4Rh.js +1 -0
  218. package/dist/register-impl-C7rENvPK.js +424 -0
  219. package/dist/{elements/chunks/resizable-D181b4fM.js → resizable-Cp9HUYih.js} +1 -1
  220. package/dist/rotate-ccw-0DLRDHH5.js +1 -0
  221. package/dist/rotate-cw-DOB9IGcU.js +1 -0
  222. package/dist/schemas/form.schema.json +21 -1
  223. package/dist/schemas/tool-defs.d.ts +11 -1
  224. package/dist/schemas.js +81 -81
  225. package/dist/scroll-area-emVmWP4K.js +1 -0
  226. package/dist/scroll-button-CeP_gv1x.js +1 -0
  227. package/dist/select-CWmu00tS.js +1 -0
  228. package/dist/{elements/chunks/separator-CeJHQqLW.js → separator-CE6vly6z.js} +1 -1
  229. package/dist/{elements/chunks/settings-CqaHgJF9.js → settings-CE-78SvZ.js} +1 -1
  230. package/dist/{elements/chunks/settings-group-CjqjLCOn.js → settings-group-ZFWNxFQR.js} +1 -1
  231. package/dist/{elements/chunks/skeleton-D8akBnKS.js → skeleton-BebdP4mf.js} +1 -1
  232. package/dist/slider-BAKRYUlz.js +1 -0
  233. package/dist/{solid-BtdqNZI7.js → solid-BE5ui6sy.js} +8727 -7212
  234. package/dist/{solid-CnavwBye.js → solid-DFhsce3O.js} +7015 -5886
  235. package/dist/solid.d.ts +10 -0
  236. package/dist/solid.js +240 -234
  237. package/dist/solid.server.js +240 -234
  238. package/dist/source-B0FlguSx.js +1 -0
  239. package/dist/star-CBMZvLuN.js +1 -0
  240. package/dist/state/index.d.ts +1 -1
  241. package/dist/state/mock.d.ts +32 -2
  242. package/dist/state.js +133 -108
  243. package/dist/{elements/chunks/store-Cjq0qwYN.js → store-7eoadydQ.js} +1 -1
  244. package/dist/svelte--5p79yCD.js +1 -15
  245. package/dist/switch-CViARZCy.js +1 -0
  246. package/dist/tasks-card-MjCcOhR_.js +1 -0
  247. package/dist/text-shimmer-DKlwRF2G.js +1 -0
  248. package/dist/textarea-3ay2Me2-.js +1 -0
  249. package/dist/theme.tokens.css +82 -13
  250. package/dist/{elements/chunks/thumbs-up-DX2Ijk3H.js → thumbs-up-DQcu2HMO.js} +1 -1
  251. package/dist/toast-store-C6yKOhbk.js +1 -0
  252. package/dist/{elements/chunks/tool-DKQ2D1DP.js → tool-BCYNlfKy.js} +1 -1
  253. package/dist/{elements/chunks/tooltip-B0G99y8w.js → tooltip-05zI4hjs.js} +1 -1
  254. package/dist/trash-2-BR1RxGky.js +1 -0
  255. package/dist/{elements/chunks/triangle-alert-F9cyUEyy.js → triangle-alert-DHohDOCy.js} +1 -1
  256. package/dist/tsx-B8rCNbgL.js +1 -6
  257. package/dist/typescript-RycA9KXf.js +1 -6
  258. package/dist/ui/checkbox-group.d.ts +83 -0
  259. package/dist/ui/checkbox.d.ts +40 -0
  260. package/dist/ui/dock.d.ts +22 -0
  261. package/dist/ui/icon.d.ts +3 -0
  262. package/dist/ui/input.d.ts +48 -2
  263. package/dist/ui/radio.d.ts +85 -0
  264. package/dist/ui/select.d.ts +71 -0
  265. package/dist/ui/slider.d.ts +65 -0
  266. package/dist/ui/switch.d.ts +9 -2
  267. package/dist/upload-BbGW6A_u.js +1 -0
  268. package/dist/url-scheme-policy-DHpoTJwB.js +1 -0
  269. package/dist/use-card-resolution-CJW4grFa.js +1 -0
  270. package/dist/{variant-aurora-B8II3-I1.js → variant-aurora-BUOVgPOB.js} +2 -2
  271. package/dist/{variant-aurora-CMNWOSJR.js → variant-aurora-CUsUJvFI.js} +2 -2
  272. package/dist/{variant-aurora-CcuDMWwQ.js → variant-aurora-CW2i4bfr.js} +1 -1
  273. package/dist/{elements/chunks/variant-aurora-qt6Zct8M.js → variant-aurora-xiMPty8f.js} +1 -1
  274. package/dist/{variant-custom-L16JLLZy.js → variant-custom-BQtOnmeO.js} +1 -1
  275. package/dist/{variant-custom-C714mqKl.js → variant-custom-CAm9L-E5.js} +2 -2
  276. package/dist/{variant-custom-BdvYC7af.js → variant-custom-CAnzzppW.js} +2 -2
  277. package/dist/{elements/chunks/variant-custom-tJp22_BQ.js → variant-custom-D91HjAKz.js} +1 -1
  278. package/dist/{variant-wave-ecwykeyL.js → variant-wave-Ca1Ls4_y.js} +2 -2
  279. package/dist/{variant-wave-D7ruiA1W.js → variant-wave-CxX39DKd.js} +2 -2
  280. package/dist/{elements/chunks/variant-wave-CaQ5ti39.js → variant-wave-DYyzIIZv.js} +1 -1
  281. package/dist/{variant-wave-2S4La2Ka.js → variant-wave-uY5crU_K.js} +1 -1
  282. package/dist/vue-BmIZj4XD.js +1 -33
  283. package/dist/x-C5m1JFgi.js +1 -0
  284. package/frameworks/react/index.tsx +198 -20
  285. package/llms-full.txt +1178 -21
  286. package/llms.txt +6 -3
  287. package/package.json +17 -4
  288. package/src/agent-tooling/catalog/invariants.ts +1 -1
  289. package/src/agent-tooling/catalog/surfaces.ts +72 -0
  290. package/src/agent-tooling/construct/cli-entry.ts +8 -0
  291. package/src/agent-tooling/construct/cli.ts +131 -0
  292. package/src/agent-tooling/construct/codegen.ts +1353 -0
  293. package/src/agent-tooling/construct/construct.v1.schema.json +250 -0
  294. package/src/agent-tooling/construct/dev.ts +148 -0
  295. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +7 -0
  296. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +44 -0
  297. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +23 -0
  298. package/src/agent-tooling/construct/schema.ts +371 -0
  299. package/src/agent-tooling/mcp/server.ts +2 -1
  300. package/src/agent-tooling/mcp/tools/construct.ts +130 -0
  301. package/src/agent-tooling/mcp/tools/debug.ts +126 -4
  302. package/src/agent-tooling/mcp/tools/reference.ts +104 -3
  303. package/src/agent-tooling/recipes/composed-thread.ts +714 -0
  304. package/src/agent-tooling/recipes/index.ts +22 -0
  305. package/src/agent-tooling/recipes/types.ts +32 -0
  306. package/src/agent-tooling/registry.ts +5 -0
  307. package/src/components/attachment-types.ts +7 -0
  308. package/src/components/audio-visualizer/fit-scale.ts +1 -1
  309. package/src/components/card-renderer.tsx +39 -8
  310. package/src/components/card.tsx +10 -2
  311. package/src/components/chat-scope-picker.tsx +2 -2
  312. package/src/components/chat-thread.tsx +72 -9
  313. package/src/components/choice-card.tsx +102 -37
  314. package/src/components/coachmark.tsx +1 -1
  315. package/src/components/code-block.tsx +2 -2
  316. package/src/components/composer.tsx +89 -15
  317. package/src/components/confirm-card.tsx +20 -4
  318. package/src/components/conversation-item.tsx +33 -9
  319. package/src/components/conversation-list.tsx +25 -10
  320. package/src/components/empty.tsx +14 -3
  321. package/src/components/file-tree.tsx +5 -1
  322. package/src/components/form-widgets.tsx +257 -195
  323. package/src/components/form.tsx +297 -9
  324. package/src/components/loader.tsx +12 -5
  325. package/src/components/message-skills.tsx +1 -1
  326. package/src/components/message.tsx +71 -11
  327. package/src/components/prompt-input.tsx +7 -1
  328. package/src/components/prompt-suggestion.tsx +4 -1
  329. package/src/components/reasoning.tsx +30 -3
  330. package/src/components/response-compare.tsx +2 -2
  331. package/src/components/scroll-button.tsx +56 -4
  332. package/src/components/source.tsx +6 -1
  333. package/src/components/tasks-card.tsx +58 -16
  334. package/src/components/thread.tsx +10 -1
  335. package/src/components/toast.tsx +1 -1
  336. package/src/components/tool-types.ts +9 -0
  337. package/src/elements/attachments.tsx +3 -1
  338. package/src/elements/chat-workspace.tsx +1 -1
  339. package/src/elements/chat.tsx +22 -4
  340. package/src/elements/checkbox-group.tsx +164 -0
  341. package/src/elements/checkbox.tsx +134 -0
  342. package/src/elements/compiled.css +1 -1
  343. package/src/elements/composer.tsx +12 -1
  344. package/src/elements/conversation-item.tsx +62 -22
  345. package/src/elements/conversation-list.tsx +2 -2
  346. package/src/elements/define-entry.ts +12 -0
  347. package/src/elements/dock.tsx +11 -0
  348. package/src/elements/element-data-types.ts +40 -0
  349. package/src/elements/element-manifest.json +24 -0
  350. package/src/elements/element-meta.json +736 -46
  351. package/src/elements/element-nonscalar.json +15 -0
  352. package/src/elements/element-types.d.ts +362 -24
  353. package/src/elements/feedback-bar.tsx +5 -0
  354. package/src/elements/icon-names.json +29 -0
  355. package/src/elements/input.tsx +312 -23
  356. package/src/elements/message.tsx +2 -0
  357. package/src/elements/pane-grid.tsx +111 -0
  358. package/src/elements/prompt-input.tsx +8 -2
  359. package/src/elements/radio-group.tsx +129 -0
  360. package/src/elements/register-impl.ts +6 -0
  361. package/src/elements/scroll-button.tsx +54 -6
  362. package/src/elements/select.tsx +165 -0
  363. package/src/elements/slider.tsx +171 -0
  364. package/src/elements/slots.ts +1 -1
  365. package/src/elements/styles.css +89 -3
  366. package/src/elements/thread.tsx +2 -0
  367. package/src/elements/toast.tsx +14 -1
  368. package/src/index.ts +2 -1
  369. package/src/primitives/card-data-types.ts +49 -0
  370. package/src/primitives/card-host.tsx +4 -2
  371. package/src/primitives/card-routing.ts +7 -56
  372. package/src/primitives/card-schemas/form.schema.json +21 -1
  373. package/src/primitives/card-validate.ts +10 -2
  374. package/src/primitives/chat-config.tsx +33 -6
  375. package/src/primitives/field-mask.ts +256 -0
  376. package/src/primitives/field-semantics.ts +115 -0
  377. package/src/primitives/input-mask.ts +853 -0
  378. package/src/primitives/toast-store.ts +66 -4
  379. package/src/primitives/url-scheme-policy.ts +70 -0
  380. package/src/primitives/use-resize-observer.ts +2 -2
  381. package/src/schemas/tool-defs.ts +12 -2
  382. package/src/solid.ts +10 -0
  383. package/src/state/index.ts +1 -1
  384. package/src/state/mock.ts +92 -6
  385. package/src/ui/agent-card.tsx +2 -2
  386. package/src/ui/avatar.tsx +1 -1
  387. package/src/ui/checkbox-group.tsx +153 -0
  388. package/src/ui/checkbox.tsx +63 -0
  389. package/src/ui/dock.tsx +145 -6
  390. package/src/ui/icon.tsx +53 -0
  391. package/src/ui/input.tsx +249 -9
  392. package/src/ui/kbd.tsx +1 -1
  393. package/src/ui/nav.tsx +1 -1
  394. package/src/ui/pane-group.tsx +2 -2
  395. package/src/ui/radio.tsx +150 -0
  396. package/src/ui/select.tsx +168 -0
  397. package/src/ui/slider.tsx +178 -0
  398. package/src/ui/switch.tsx +49 -18
  399. package/src/utils/cn.ts +11 -5
  400. package/theme.css +84 -13
  401. package/dist/elements/chunks/action-icons-D9u3OzYW.js +0 -1
  402. package/dist/elements/chunks/arrow-left-CVh1TeN7.js +0 -1
  403. package/dist/elements/chunks/artifact-BkYcfIlZ.js +0 -1
  404. package/dist/elements/chunks/attachments-DwfNlubq.js +0 -1
  405. package/dist/elements/chunks/badge-Q0-Cmwzz.js +0 -1
  406. package/dist/elements/chunks/bash-InADTalH.js +0 -1
  407. package/dist/elements/chunks/card-renderer-3Dyl-FpN.js +0 -1
  408. package/dist/elements/chunks/card-routing-BK09BdmL.js +0 -1
  409. package/dist/elements/chunks/check-B5kBPKeo.js +0 -1
  410. package/dist/elements/chunks/chevron-down-DZ1GS39h.js +0 -1
  411. package/dist/elements/chunks/chevron-right-CvP7OUd2.js +0 -1
  412. package/dist/elements/chunks/choice-card-D4QUIOWZ.js +0 -1
  413. package/dist/elements/chunks/circle-CDf9g6MQ.js +0 -1
  414. package/dist/elements/chunks/circle-check-CA47Nqbz.js +0 -1
  415. package/dist/elements/chunks/circle-x-CJ_HVbC8.js +0 -1
  416. package/dist/elements/chunks/composer-Byve-n8K.js +0 -69
  417. package/dist/elements/chunks/confirm-card-B0flE3MN.js +0 -1
  418. package/dist/elements/chunks/controllable-DTwTIlwp.js +0 -1
  419. package/dist/elements/chunks/conversation-item-BDztezOG.js +0 -1
  420. package/dist/elements/chunks/copy-Nf-kqxXH.js +0 -1
  421. package/dist/elements/chunks/core-AYMC6_lb.js +0 -12
  422. package/dist/elements/chunks/css-M7EaDHN_.js +0 -1
  423. package/dist/elements/chunks/default-input-C2iLFq0b.js +0 -1
  424. package/dist/elements/chunks/define-wjHR1MkU.js +0 -1
  425. package/dist/elements/chunks/download-C4V7tBdb.js +0 -1
  426. package/dist/elements/chunks/embed-D3KewsIJ.js +0 -1
  427. package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +0 -141
  428. package/dist/elements/chunks/file-text-D1G8khle.js +0 -1
  429. package/dist/elements/chunks/folder-WW2LGLid.js +0 -1
  430. package/dist/elements/chunks/form-CQirdC4W.js +0 -1
  431. package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +0 -1
  432. package/dist/elements/chunks/github-light-JYsPkUQd.js +0 -1
  433. package/dist/elements/chunks/hover-card-CJJkfHTK.js +0 -1
  434. package/dist/elements/chunks/html-CPZ3oZQ7.js +0 -1
  435. package/dist/elements/chunks/icon-Cfgmf4fa.js +0 -1
  436. package/dist/elements/chunks/info-DX3YMOt6.js +0 -1
  437. package/dist/elements/chunks/input-BtW9U6Sq.js +0 -1
  438. package/dist/elements/chunks/javascript-C25yR2R2.js +0 -1
  439. package/dist/elements/chunks/json-DxJze_jm.js +0 -1
  440. package/dist/elements/chunks/kbd-LGXwuT_V.js +0 -1
  441. package/dist/elements/chunks/link-2My69BqT.js +0 -1
  442. package/dist/elements/chunks/loader-iOxc_Tu-.js +0 -1
  443. package/dist/elements/chunks/message-VMZohrXx.js +0 -1
  444. package/dist/elements/chunks/message-circle-CpXMM-_n.js +0 -1
  445. package/dist/elements/chunks/message-square-DxcWtETQ.js +0 -1
  446. package/dist/elements/chunks/message-tZmV2A3p.js +0 -1
  447. package/dist/elements/chunks/paperclip-CRZVp4z_.js +0 -1
  448. package/dist/elements/chunks/progress-bar-DNy66e_E.js +0 -1
  449. package/dist/elements/chunks/prompt-suggestion-Bn64Nl7L.js +0 -1
  450. package/dist/elements/chunks/reasoning-Emn9N4-T.js +0 -1
  451. package/dist/elements/chunks/rotate-cw-CPWe37D9.js +0 -1
  452. package/dist/elements/chunks/scroll-area-ClZkZxIk.js +0 -1
  453. package/dist/elements/chunks/scroll-button-DPE-t3x_.js +0 -1
  454. package/dist/elements/chunks/share-CyfnNEqp.js +0 -1
  455. package/dist/elements/chunks/source-UWCvmVak.js +0 -1
  456. package/dist/elements/chunks/star-DoHFAikQ.js +0 -1
  457. package/dist/elements/chunks/svelte--5p79yCD.js +0 -1
  458. package/dist/elements/chunks/tasks-card-CmZ5xh6v.js +0 -1
  459. package/dist/elements/chunks/text-shimmer-DYn09zrz.js +0 -1
  460. package/dist/elements/chunks/textarea-skiGHURM.js +0 -1
  461. package/dist/elements/chunks/toast-store-CFnQpThX.js +0 -1
  462. package/dist/elements/chunks/tsx-B8rCNbgL.js +0 -1
  463. package/dist/elements/chunks/typescript-RycA9KXf.js +0 -1
  464. package/dist/elements/chunks/use-card-resolution-DoA2f_EU.js +0 -1
  465. package/dist/elements/chunks/vue-BmIZj4XD.js +0 -1
  466. package/dist/elements/chunks/x-B6UnOiLw.js +0 -1
  467. package/dist/llms/llms-full.txt +0 -2949
  468. package/dist/llms/llms.txt +0 -156
  469. package/dist/register-impl-DpE7icIb.js +0 -293
  470. package/dist/ui/stat.d.ts +0 -16
  471. package/src/ui/stat.tsx +0 -41
  472. /package/dist/{elements/chunks/card-tags-D8lZ-C_U.js → card-tags-D8lZ-C_U.js} +0 -0
  473. /package/dist/{elements/chunks/link-preview-DNILK391.js → link-preview-DNILK391.js} +0 -0
  474. /package/dist/{elements/chunks/slots-DaNjX0rc.js → slots-DaNjX0rc.js} +0 -0
@@ -198,7 +198,7 @@ export interface KaiArtifactElement extends HTMLElement {
198
198
  export interface KaiAttachmentsElement extends HTMLElement {
199
199
  /** Color mode (`auto` follows prefers-color-scheme). */
200
200
  theme?: "light" | "dark" | "auto";
201
- /** The attachments to render. Omit (or pass an empty array) for the empty state, which shows `emptyText` if set and nothing otherwise. Set as a JS property (array). */
201
+ /** The attachments to render. Omit (or pass an empty array) for the empty state, which shows `emptyText` if set and nothing otherwise. Set as a JS property (array). Each item's `url` must be a `data:` URI or an https URL, never `URL.createObjectURL`: a `blob:` URL previews here but the wire encoders (`toOpenAIMessages`/`toAnthropicMessages`) refuse it. */
202
202
  items: { id: string; type: "file" | "source-document"; filename?: string; mediaType?: string; url?: string; title?: string }[];
203
203
  /** Layout: `grid` = visual tiles, `inline` = icon + label chips, `list` = rows. */
204
204
  variant?: "grid" | "inline" | "list";
@@ -333,7 +333,7 @@ export interface KaiCardsElement extends HTMLElement {
333
333
  /** JSON Schemas for the card types this app renders, keyed by envelope type. The companion of `types`, which says what DRAWS a card while this says what a VALID one looks like. An OBJECT, so it is a JS property only: `el.schemas = { 'pricing-table': pricingSchema }`, never an attribute. `createCardRegistry(...).validationSchemas` is exactly this shape. Without it the kit validates its own seven built-ins and leaves your own card type, the one your app actually cares about, as the only unchecked thing on screen. A schema here WINS over a built-in of the same name, matching `mergeCardTags`, where your entry is spread over ours. Typed `Record<string, object>` rather than `Record<string, JsonSchema>` deliberately: an imported `.json` schema widens `"type"` to `string`, and an authored one carries `$schema`/`title`/`description`/`additionalProperties`, so the tighter type would reject both of the normal ways to supply one. See `CardSchemaMap` in components/card-renderer.tsx. */
334
334
  schemas?: Record<string, object>;
335
335
  /** Optional CardPolicy handling child events. Property: `el.policy`. */
336
- policy?: { onSubmit?: (cardId: string, data: unknown) => void; onAction?: (cardId: string, action: string, payload?: unknown) => void; onSendPrompt?: (text: string, opts: { mode: "compose" | "send"; context?: unknown; }) => void; onOpen?: (url: string, target: "tab" | "artifact") => void; onState?: (cardId: string, patch: unknown) => void; onDismiss?: (cardId: string) => void; onReopen?: (cardId: string) => void; onError?: (cardId: string, message: string) => void; maxSendPromptMode?: "compose" | "send" };
336
+ policy?: { onSubmit?: ((cardId: string, data: unknown) => void); onAction?: ((cardId: string, action: string, payload?: unknown) => void); onSendPrompt?: ((text: string, opts: { mode: "compose" | "send"; context?: unknown; }) => void); onOpen?: ((url: string, target: "tab" | "artifact") => void); onState?: ((cardId: string, patch: unknown) => void); onDismiss?: ((cardId: string) => void); onReopen?: ((cardId: string) => void); onError?: ((cardId: string, message: string) => void); maxSendPromptMode?: "compose" | "send" };
337
337
  /** Validate each envelope's `data` against the schema for its type before rendering it, using a built-in's own schema or yours from `schemas`. Default `true`; set `validate-cards="false"` (or `el.validateCards = false`) to opt out. A hard failure (wrong type, a missing required field) renders a diagnostic naming the field instead of the card; a soft failure (bounds) renders the card unchanged. Both emit a contract `error` event. On in production too: a model emitting a bad shape is a production failure mode, so stripping the check there would hide it from exactly the person who needs to see it. */
338
338
  validateCards?: boolean;
339
339
  /** Programmatically resolve a child card by id: set that envelope's `resolution` so the child re-renders into its read-only/resolved view. The imperative twin of the consumer mutating the cards array. No-op for an unknown id. */
@@ -384,6 +384,10 @@ export interface KaiChatElement extends HTMLElement {
384
384
  codeTheme?: string;
385
385
  /** Enable Shiki syntax highlighting in code blocks. Turn off to render plain `<pre>` blocks (lighter, no highlighter load). Default true. */
386
386
  codeHighlight?: boolean;
387
+ /** How `reasoning` parts render across the thread. `'full'` (default) is the current collapsible-disclosure behavior; `'compact'` shows only a shimmer loader while a reasoning part streams and nothing once it settles (no expandable detail); `'off'` renders reasoning parts not at all. Forwarded to every `MessageBody` as `reasoningMode`. */
388
+ reasoning?: "full" | "compact" | "off";
389
+ /** Seeds the reasoning disclosure open AND keeps it tracking the stream (open while streaming, closes when it settles): the pre-Task-19f `full` behavior. Default false/absent: the panel starts closed (just the "Thinking" shimmer chip) and only opens on click, the current default (owner ruling, 2026-08-26). Meaningless when `reasoning` is `'compact'` or `'off'`. Forwarded to every `MessageBody` as `reasoningDefaultOpen`. */
390
+ reasoningOpen?: boolean;
387
391
  /** Optional header title shown on the left of the header. */
388
392
  chatTitle?: string;
389
393
  /** Optional model list. When set (>1 model) a ModelSwitcher is shown in the header and a `kai-model-change` event fires on selection. */
@@ -410,6 +414,8 @@ export interface KaiChatElement extends HTMLElement {
410
414
  composerActions?: boolean;
411
415
  /** INJECT: footer row below the composer (disclaimers, token meter, …). */
412
416
  footer?: boolean;
417
+ /** When `false`, hides the built-in paperclip attach button. Defaults to `true` (undeclared keeps today's behavior: attach visible), matching `DefaultPromptInput`'s own default: only an explicit `false` hides it. */
418
+ attach?: boolean;
413
419
  /** Show a web-search (Globe) button in the input toolbar; calls `onWebSearch`. */
414
420
  webSearch?: boolean;
415
421
  /** Show a Voice (Mic) button in the input toolbar; fires a `voice` event. */
@@ -440,6 +446,48 @@ export interface KaiChatElement extends HTMLElement {
440
446
  scrollToBottom(behavior?: "auto" | "instant" | "smooth"): void;
441
447
  }
442
448
 
449
+ export interface KaiCheckboxElement extends HTMLElement {
450
+ /** Color mode (`auto` follows prefers-color-scheme). */
451
+ theme?: "light" | "dark" | "auto";
452
+ /** Controlled checked state. Settable and reflected to the `checked` attribute. `el.checked = true` (or `<kai-checkbox checked>`) drives it; ticking the box updates it and fires `kai-change`. Read `el.checked` for live state. */
453
+ checked?: boolean;
454
+ /** Initial checked state on mount (uncontrolled seed). Bare attribute (`<kai-checkbox default-checked>`) turns it on. */
455
+ defaultChecked?: boolean;
456
+ /** The mixed state, for a parent box whose children are partly ticked. Visual plus an accessibility hint: the box still reports `checked === false`. */
457
+ indeterminate?: boolean;
458
+ /** Disable interaction. */
459
+ disabled?: boolean;
460
+ /** Set the native `required` attribute, and nothing more. Whether an unticked box is an error is the application's rule, not the kit's. */
461
+ required?: boolean;
462
+ /** Accessible label. The visible text beside the box is the consumer's to render. */
463
+ label?: string;
464
+ /** Form-control name (paired with `value`). */
465
+ name?: string;
466
+ /** Submitted value when checked (paired with `name`). Defaults to `'on'`. */
467
+ value?: string;
468
+ /** Flip the box and fire `kai-change` (no-op while disabled). */
469
+ toggle(): void;
470
+ /** Focus the inner input (the host element can't reach it). */
471
+ focus(options?: FocusOptions): void;
472
+ }
473
+
474
+ export interface KaiCheckboxGroupElement extends HTMLElement {
475
+ /** Color mode (`auto` follows prefers-color-scheme). */
476
+ theme?: "light" | "dark" | "auto";
477
+ /** The choices, top to bottom. Set as a JS PROPERTY (array), never an attribute. Rendered in full: the kit never truncates, re-orders or de-duplicates them. */
478
+ options: { value: string; label: string; description?: undefined | string; disabled?: undefined | boolean }[];
479
+ /** The FIRST selected value. Settable and reflected to the `value` attribute, so `:host([value])` and `el.value` see live state, and a seed can be written in markup. Writing it makes that the whole selection; to read or drive the rest, use `el.values`. */
480
+ value?: string;
481
+ /** The shared form-control name every box carries, so `FormData.getAll(name)` reads the whole selection back under one key. NO DEFAULT, unlike `<kai-radio-group>`. A radio set needs a shared `name` for the browser to make it exclusive and arrow-navigable, so one is generated when none is given; checkboxes are independent controls and behave correctly with no name at all. Generating one here would submit the selection under a random key, which is worse than submitting nothing. The element is NOT form-associated (no `ElementInternals`, no `setFormValue()`), the same known gap `<kai-input>` records: the boxes live in a shadow root, so a surrounding `<form>` collects nothing from them whether or not `name` is set. Read `el.values`. The name still lands on every inner input, so it is right the day form association arrives. */
482
+ name?: string;
483
+ /** Disable every row. Individual rows carry their own `disabled`. */
484
+ disabled?: boolean;
485
+ /** Accessible name for the group. */
486
+ label?: string;
487
+ /** Focus the group's first box. Not "the first ticked one", which is `<kai-radio-group>`'s rule: a radio group is ONE tab stop that lands on the selection, while every checkbox here is its own tab stop, so the entry point is simply the top of the list. */
488
+ focus(options?: FocusOptions): void;
489
+ }
490
+
443
491
  export interface KaiCheckpointElement extends HTMLElement {
444
492
  /** Color mode (`auto` follows prefers-color-scheme). */
445
493
  theme?: "light" | "dark" | "auto";
@@ -634,9 +682,9 @@ export interface KaiContextElement extends HTMLElement {
634
682
  export interface KaiConversationItemElement extends HTMLElement {
635
683
  /** Color mode (`auto` follows prefers-color-scheme). */
636
684
  theme?: "light" | "dark" | "auto";
637
- /** The row's identity, handed to the container's selection contract. In the element this is the `conversation-id` attribute (host `id` is the fallback). */
685
+ /** The row's identity: the `conversation-id` attribute (host `id` is the fallback). Inside `<kai-conversations>` it is handed to the container's selection contract (`kai-conversation-select`); standalone it is the `id` in this element's own `kai-select` detail. */
638
686
  conversationId?: string;
639
- /** Selected state. Reflected as `aria-current` on the row body and a `data-active` styling hook on the row; the container drives it from its `activeId`. */
687
+ /** Selected state. Reflected as `aria-current` on the row body and a `data-active` styling hook on the row; inside a container the container drives it from its `activeId`, standalone you set it yourself. */
640
688
  active?: boolean;
641
689
  /** Dense single-line row padding. */
642
690
  compact?: boolean;
@@ -709,6 +757,8 @@ export interface KaiDockElement extends HTMLElement {
709
757
  unread?: boolean;
710
758
  /** Disable the launcher; `show()` and `toggle()` are gated on it. */
711
759
  disabled?: boolean;
760
+ /** Suppress the dock's own built-in mobile close X. Set this when your slotted panel content supplies its own close affordance (e.g. a `<kai-chat slot="header-end">` close button), otherwise the two stack. TRADEOFF: the mobile panel reserves a padding band above its content so the built-in X never paints over slotted content; that band stays reserved unless you set this true, so only set it once your own control is actually in place. Attribute: `hide-close`. */
761
+ hideClose?: boolean;
712
762
  /** Where focus lands on open: `content` (default, the first element you slotted), `panel`, or `none`. Attribute: `focus-on-open`. */
713
763
  focusOnOpen?: "content" | "panel" | "none";
714
764
  /** Open it programmatically (no-op while disabled). */
@@ -834,7 +884,7 @@ export interface KaiFormElement extends HTMLElement {
834
884
  /** Color mode (`auto` follows prefers-color-scheme). */
835
885
  theme?: "light" | "dark" | "auto";
836
886
  /** The form definition: a JSON Schema (`type:'object'`) + `x-kai-*` UI hints (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { type:'object', properties:{…} }`. Import the `FormDefinition` type from `@kitn.ai/ui` for the full shape. It IS self-referential (`FormField.properties` is another `FormField` map), and the generated `element-types.d.ts` inlines every named type, so the shipped declaration bottoms out in a `Record<string, unknown>` placeholder one level down rather than carrying the recursion. That is why `FormDefinition` is a `type` alias: an interface gets no implicit index signature, so it would not be assignable to that placeholder. */
837
- data?: { type: "object"; title?: string; description?: string; required?: string[]; properties: Record<string, { type: "string" | "number" | "integer" | "boolean" | "array" | "object"; title?: string; description?: string; default?: unknown; enum?: unknown[]; format?: "email" | "uri" | "url" | "date" | "date-time" | "time"; minimum?: number; maximum?: number; minLength?: number; maxLength?: number; pattern?: string; minItems?: number; maxItems?: number; items?: Record<string, unknown> | { enum: unknown[] }; properties?: Record<string, Record<string, unknown>>; required?: string[]; readOnly?: boolean; "x-kai-widget"?: "textarea" | "slider" | "rating" | "radio" | "select" | "checkbox" | "password" | "switch"; "x-kai-placeholder"?: string; "x-kai-step"?: number }>; "x-kai-order"?: string[]; "x-kai-inlineMax"?: number; "x-kai-submitLabel"?: string; "x-kai-dismissible"?: boolean; "x-kai-actions"?: { id: string; label: string; variant?: "default" | "ghost" | "outline" }[] };
887
+ data?: { type: "object"; title?: string; description?: string; required?: string[]; properties: Record<string, { type: "string" | "number" | "integer" | "boolean" | "array" | "object"; title?: string; description?: string; default?: unknown; enum?: unknown[]; format?: "email" | "uri" | "url" | "date" | "date-time" | "time"; minimum?: number; maximum?: number; minLength?: number; maxLength?: number; pattern?: string; minItems?: number; maxItems?: number; items?: Record<string, unknown> | { enum: unknown[] }; properties?: Record<string, Record<string, unknown>>; required?: string[]; readOnly?: boolean; "x-kai-widget"?: "textarea" | "slider" | "rating" | "radio" | "select" | "checkbox" | "password" | "switch"; "x-kai-placeholder"?: string; "x-kai-step"?: number; "x-kai-format"?: "tel" | "ssn" | "credit-card" | "custom"; "x-kai-mask"?: string; "x-kai-mask-guide"?: string }>; "x-kai-order"?: string[]; "x-kai-inlineMax"?: number; "x-kai-submitLabel"?: string; "x-kai-dismissible"?: boolean; "x-kai-actions"?: { id: string; label: string; variant?: "default" | "ghost" | "outline" }[] };
838
888
  /** Stable card id correlating every emitted CardEvent. Attribute: `card-id`. */
839
889
  cardId?: string;
840
890
  /** Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. */
@@ -911,7 +961,7 @@ export interface KaiInputElement extends HTMLElement {
911
961
  theme?: "light" | "dark" | "auto";
912
962
  /** Native input type: `text` (default) · `email` · `url` · `search` · `tel` · `password` · `number`. Single-line only. */
913
963
  type?: string;
914
- /** Controlled value. Settable and reflected to the `value` attribute. `el.value = 'hi'` drives it (no event); typing updates it and fires `kai-input`. Read `el.value` for live state. */
964
+ /** Controlled value, and always the CANONICAL one when a mask is active: digits for `tel` / `ssn` / `credit-card`, the formatted text for `custom`. Settable and reflected to the `value` attribute. `el.value = '5551234567'` drives it (no event) and is re-fitted to the mask on the way in, so the field shows `555-123-4567`. Read `el.value` for live state; the formatted text rides along on every `kai-input` / `kai-change` detail as `formattedValue`. */
915
965
  value?: string;
916
966
  /** Placeholder shown when empty. */
917
967
  placeholder?: string;
@@ -937,11 +987,25 @@ export interface KaiInputElement extends HTMLElement {
937
987
  autocomplete?: string;
938
988
  /** Virtual-keyboard hint forwarded to the inner input (e.g. `numeric`, `email`). */
939
989
  inputmode?: string;
990
+ /** Mask pattern: `#` a digit, `@` a letter or digit, `*` an obscurable letter or digit, and every other character a positional literal (`@@@-####` → `CHG-4821`). The literal `default` is the opt-in sentinel: it resolves to the default format of `semantic` (`tel` → `###-###-####`). A bare `semantic` never starts masking on its own, so an opt-in token is what turns tier 2 on. */
991
+ format?: string;
992
+ /** Placeholder guide shown at unfilled positions, aligned position for position with `format`: `mm/dd/yyyy` against `##/##/####`. Spaces are a valid guide character, so a guide of blanks and separators is how a phone field shows its shape without showing letters. Without a guide the field shows only up to the last typed character. A guide is a visual aid, never an accessible name: keep the `hint` text as well. */
993
+ guide?: string;
994
+ /** Semantic field type: `tel` · `ssn` · `credit-card` · `custom`. On its own it sets `inputmode` / `autocomplete` / `spellcheck` / `autocorrect` / `autocapitalize` and decides the canonical value; it never starts masking by itself. */
995
+ semantic?: "credit-card" | "custom" | "ssn" | "tel";
996
+ /** Case folding applied to typed and pasted text: `preserve` (default) · `upper` · `lower`. Attribute: `case-mode`. */
997
+ caseMode?: "preserve" | "upper" | "lower";
998
+ /** What a copy or cut of a masked field puts on the clipboard: `canonical` (default) · `formatted` · `obscured` · `blocked`. Attribute: `copy-policy`. */
999
+ copyPolicy?: "formatted" | "canonical" | "obscured" | "blocked";
940
1000
  /** Focus the inner input (the host can't reach into the shadow root). */
941
1001
  focus(options?: FocusOptions): void;
942
1002
  /** Select the inner input's text. */
943
1003
  select(): void;
944
- /** Empty the value and fire `kai-change` with `''`. */
1004
+ /** The canonical value: digits for `tel` / `ssn` / `credit-card`, the formatted text for `custom`, and the field text when no mask is on. Identical to reading `el.value`, under the name backends use for the submitted form of a masked field. The mask engine has a third, narrower notion of raw (the fill characters with no literals at all) and that one is internal: it is not what any backend wants and it is not exposed here. */
1005
+ getRawValue(): string;
1006
+ /** The text on screen, literals and guide included. The counterpart to `formattedValue` on the `kai-input` / `kai-change` details, for a consumer that needs it outside an event. */
1007
+ getFormattedValue(): string;
1008
+ /** Empty the value and fire `kai-change` with `''`. On a masked field this resets the mask itself, not just the text on screen, so the next character starts over. */
945
1009
  clear(): void;
946
1010
  }
947
1011
 
@@ -1117,6 +1181,21 @@ export interface KaiPaneElement extends HTMLElement {
1117
1181
  status?: { tone: "working" | "idle" | "done" | "error" | "blocked"; label?: string; pulse?: boolean };
1118
1182
  }
1119
1183
 
1184
+ export interface KaiPaneGridElement extends HTMLElement {
1185
+ /** Color mode (`auto` follows prefers-color-scheme). */
1186
+ theme?: "light" | "dark" | "auto";
1187
+ /** Minimum width of every pane, in px, before columns drop / the grid scrolls. Defaults to `280`. Attribute: `min-pane-width`. */
1188
+ minPaneWidth?: number;
1189
+ /** Minimum height of every pane, in px, before the grid scrolls vertically. Defaults to `200`. Attribute: `min-pane-height`. */
1190
+ minPaneHeight?: number;
1191
+ /** Column cap when the container is wide (default `3`). Attribute: `max-columns`. */
1192
+ maxColumns?: number;
1193
+ /** Gap between panes, any CSS length. Defaults to the kit gap (`var(--kai-pane-grid-gap, 0.5rem)`). Attribute: `gap`. */
1194
+ gap?: string;
1195
+ /** When set to a valid child index, render ONLY that pane full-bleed: a simple maximize hook the consumer drives (pair it with `<kai-pane>`'s `kai-maximize` event). Clear it (or point out of range) for the full tiled grid. Attribute: `maximized-index`. */
1196
+ maximizedIndex?: number | null;
1197
+ }
1198
+
1120
1199
  export interface KaiPaneGroupElement extends HTMLElement {
1121
1200
  /** Color mode (`auto` follows prefers-color-scheme). */
1122
1201
  theme?: "light" | "dark" | "auto";
@@ -1200,7 +1279,7 @@ export interface KaiPromptInputElement extends HTMLElement {
1200
1279
  submit?: "always" | "auto";
1201
1280
  /** When `false`, hides the built-in paperclip attach button even though the element otherwise supports attachments. Use this when a `+` menu in `toolbar-start` already exposes "Add files", to avoid a duplicate control. Defaults to `true`. */
1202
1281
  attach?: boolean;
1203
- /** Attachments to seed the input with (so a consumer can pre-populate staged files without an upload). Set as a JS property; the element then manages its own attachment state from there (add via the paperclip, remove per chip). */
1282
+ /** Attachments to seed the input with (so a consumer can pre-populate staged files without an upload). Set as a JS property; the element then manages its own attachment state from there (add via the paperclip, remove per chip). Each item's `url` must be a `data:` URI or an https URL, never `URL.createObjectURL`: a `blob:` URL previews perfectly and is meaningless outside this tab, so `toOpenAIMessages`/`toAnthropicMessages` refuse it. (The built-in paperclip already stages files as `data:` URIs.) */
1204
1283
  attachments?: { id: string; type: "file" | "source-document"; filename?: string; mediaType?: string; url?: string; title?: string }[];
1205
1284
  /** Rich entity triggers. Each `{ char, kind, items }` opens a caret-anchored menu that inserts an atomic pill. Convention: `/` → skills, `@` → agents (plugins are the grouping/provenance of those items). Set as a JS property. */
1206
1285
  triggers?: { char: string; kind: string; items?: { id: string; label: string; icon?: string; description?: string; group?: string; kind?: string; promptText?: string; data?: Record<string, unknown> }[] }[];
@@ -1216,6 +1295,23 @@ export interface KaiPromptInputElement extends HTMLElement {
1216
1295
  send(): void;
1217
1296
  }
1218
1297
 
1298
+ export interface KaiRadioGroupElement extends HTMLElement {
1299
+ /** Color mode (`auto` follows prefers-color-scheme). */
1300
+ theme?: "light" | "dark" | "auto";
1301
+ /** The choices, top to bottom. Set as a JS PROPERTY (array), never an attribute. */
1302
+ options: { value: string; label: string; description?: undefined | string; disabled?: undefined | boolean }[];
1303
+ /** Controlled selected `value`. Settable and reflected to the `value` attribute. `el.value = 'degraded'` drives it; choosing a row updates it and fires `kai-change`. Read `el.value` for live state. */
1304
+ value?: string;
1305
+ /** Shared form-control name for every radio in the group. Defaults to a generated id, so the group is exclusive and keyboard-navigable even when nothing is submitted. */
1306
+ name?: string;
1307
+ /** Disable every row. Individual rows carry their own `disabled`. */
1308
+ disabled?: boolean;
1309
+ /** Accessible name for the group. */
1310
+ label?: string;
1311
+ /** Focus the group's tab stop. That is the selected radio, or the first row when nothing is selected yet. */
1312
+ focus(options?: FocusOptions): void;
1313
+ }
1314
+
1219
1315
  export interface KaiReasoningElement extends HTMLElement {
1220
1316
  /** Color mode (`auto` follows prefers-color-scheme). */
1221
1317
  theme?: "light" | "dark" | "auto";
@@ -1361,6 +1457,10 @@ export interface KaiScrollButtonElement extends HTMLElement {
1361
1457
  variant?: "outline" | "ghost" | "default";
1362
1458
  /** Button size token. Defaults to `'icon'` (square). */
1363
1459
  size?: "sm" | "md" | "lg" | "icon" | "icon-sm";
1460
+ /** The button's accessible name. It is announced whether or not the label is visible, so the text is always localisable. Defaults to `'Scroll to bottom'`. */
1461
+ label?: string;
1462
+ /** Also render `label` visibly beside the icon. Defaults to `false`, which is the icon-only button. When the text is visible it IS the accessible name, so nothing gets announced twice. */
1463
+ showLabel?: boolean;
1364
1464
  }
1365
1465
 
1366
1466
  export interface KaiSearchElement extends HTMLElement {
@@ -1395,6 +1495,31 @@ export interface KaiSegmentedElement extends HTMLElement {
1395
1495
  size?: "sm" | "md";
1396
1496
  }
1397
1497
 
1498
+ export interface KaiSelectElement extends HTMLElement {
1499
+ /** Color mode (`auto` follows prefers-color-scheme). */
1500
+ theme?: "light" | "dark" | "auto";
1501
+ /** The choices, in display order. Set as a JS PROPERTY (array), never an attribute. Rendered in full: the kit never truncates, re-orders or de-duplicates them. */
1502
+ options: { value: string; label?: undefined | string; disabled?: undefined | boolean }[];
1503
+ /** Controlled selected value. Settable and reflected to the `value` attribute. `el.value = 'high'` drives it; choosing an option updates it and fires `kai-change`. Read `el.value` for live state; for a `multiple` select read `el.values` instead. */
1504
+ value?: string;
1505
+ /** Text for a leading, disabled, empty option: the "nothing chosen yet" row. Omitted means no such row at all; there is no default wording, because inventing one would put words in your UI. */
1506
+ placeholder?: string;
1507
+ /** Allow more than one selection. Turns the control into the platform's list box, so the kit's chevron is not drawn. */
1508
+ multiple?: boolean;
1509
+ /** Force the invalid (destructive-border) state. */
1510
+ invalid?: boolean;
1511
+ /** Disable interaction. */
1512
+ disabled?: boolean;
1513
+ /** Set the native `required` attribute, and nothing more. Whether an empty select is an error is the application's rule, not the kit's. */
1514
+ required?: boolean;
1515
+ /** Accessible label for the control. */
1516
+ label?: string;
1517
+ /** Form-control name, for a native form submit. */
1518
+ name?: string;
1519
+ /** Focus the inner select (the host element can't reach it). */
1520
+ focus(options?: FocusOptions): void;
1521
+ }
1522
+
1398
1523
  export interface KaiSeparatorElement extends HTMLElement {
1399
1524
  /** Color mode (`auto` follows prefers-color-scheme). */
1400
1525
  theme?: "light" | "dark" | "auto";
@@ -1440,6 +1565,29 @@ export interface KaiSkillsElement extends HTMLElement {
1440
1565
  skills: { id: string; name: string }[];
1441
1566
  }
1442
1567
 
1568
+ export interface KaiSliderElement extends HTMLElement {
1569
+ /** Color mode (`auto` follows prefers-color-scheme). */
1570
+ theme?: "light" | "dark" | "auto";
1571
+ /** Lowest selectable value. Required: a range with no bounds is a guess, and the guess belongs to whoever knows what the number means. */
1572
+ min?: number;
1573
+ /** Highest selectable value. Required, for the same reason as `min`. */
1574
+ max?: number;
1575
+ /** Granularity. Omitted means the native default of 1; `any` means continuous. */
1576
+ step?: number | "any";
1577
+ /** Controlled value. Settable and reflected to the `value` attribute. `el.value = 40` drives it; dragging updates it and fires `kai-input` per step, `kai-change` on release. Read `el.value` for live state. */
1578
+ value?: number;
1579
+ /** Disable interaction. */
1580
+ disabled?: boolean;
1581
+ /** Accessible label for the slider. */
1582
+ label?: string;
1583
+ /** Form-control name, for a native form submit. */
1584
+ name?: string;
1585
+ /** Show the current value beside the track. Off by default. Two ways in, because one of them is not a scalar. As a bare ATTRIBUTE (`<kai-slider value-label>`) it renders the raw number. As a JS PROPERTY it also accepts a formatter function (`el.valueLabel = (v) => v + '%'`), for a slider that is not counting bare numbers. A function cannot survive an attribute, so that half is property-only. The readout is hidden from assistive tech: the slider already reports the same number, and an exposed copy would be announced twice. */
1586
+ valueLabel?: boolean | ((value: number) => string);
1587
+ /** Focus the inner range input (the host element can't reach it). */
1588
+ focus(options?: FocusOptions): void;
1589
+ }
1590
+
1443
1591
  export interface KaiSourceElement extends HTMLElement {
1444
1592
  /** Color mode (`auto` follows prefers-color-scheme). */
1445
1593
  theme?: "light" | "dark" | "auto";
@@ -1625,7 +1773,7 @@ export interface KaiThreadElement extends HTMLElement {
1625
1773
  export interface KaiToastRegionElement extends HTMLElement {
1626
1774
  /** Color mode (`auto` follows prefers-color-scheme). */
1627
1775
  theme?: "light" | "dark" | "auto";
1628
- /** The toasts to render. Newest is shown on top. Set as a JS property (array); pass a new array reference to update. Omit for an empty region, which is the normal resting state and how the imperative `toast()` API starts. */
1776
+ /** The toasts to render. Newest is shown on top. Set as a JS property (array); pass a new array reference to update. Omit for an empty region, which is the normal resting state and how the imperative `toast()` API starts. Note the handover: the first `toast()` call ADOPTS a region you placed in markup (no second region mounts) and binds the imperative store to this property, replacing any array you set. Drive a region as data OR via `toast()`, not both at once. */
1629
1777
  toasts: { id: string; message: string; variant?: "neutral" | "success" | "warning" | "error" | "info"; appearance?: "pill" | "card"; inverse?: boolean; description?: string; action?: { label: string; onAction: () => void | false }; duration?: number; dismissible?: boolean; target?: HTMLElement }[];
1630
1778
  /** Stack anchor: `'top-center'` (default), `'top-right'`, `'bottom-center'`, … */
1631
1779
  position?: "top-center" | "top-right" | "top-left" | "bottom-center" | "bottom-right" | "bottom-left";
@@ -1761,6 +1909,8 @@ declare global {
1761
1909
  'kai-cards': KaiCardsElement;
1762
1910
  'kai-chain-of-thought': KaiChainOfThoughtElement;
1763
1911
  'kai-chat': KaiChatElement;
1912
+ 'kai-checkbox': KaiCheckboxElement;
1913
+ 'kai-checkbox-group': KaiCheckboxGroupElement;
1764
1914
  'kai-checkpoint': KaiCheckpointElement;
1765
1915
  'kai-choice': KaiChoiceElement;
1766
1916
  'kai-coachmark': KaiCoachmarkElement;
@@ -1796,11 +1946,13 @@ declare global {
1796
1946
  'kai-nav': KaiNavElement;
1797
1947
  'kai-notice': KaiNoticeElement;
1798
1948
  'kai-pane': KaiPaneElement;
1949
+ 'kai-pane-grid': KaiPaneGridElement;
1799
1950
  'kai-pane-group': KaiPaneGroupElement;
1800
1951
  'kai-popover': KaiPopoverElement;
1801
1952
  'kai-progress-bar': KaiProgressBarElement;
1802
1953
  'kai-prompt-dock': KaiPromptDockElement;
1803
1954
  'kai-prompt-input': KaiPromptInputElement;
1955
+ 'kai-radio-group': KaiRadioGroupElement;
1804
1956
  'kai-reasoning': KaiReasoningElement;
1805
1957
  'kai-remote': KaiRemoteElement;
1806
1958
  'kai-resizable': KaiResizableElement;
@@ -1812,11 +1964,13 @@ declare global {
1812
1964
  'kai-scroll-button': KaiScrollButtonElement;
1813
1965
  'kai-search': KaiSearchElement;
1814
1966
  'kai-segmented': KaiSegmentedElement;
1967
+ 'kai-select': KaiSelectElement;
1815
1968
  'kai-separator': KaiSeparatorElement;
1816
1969
  'kai-setting-item': KaiSettingItemElement;
1817
1970
  'kai-settings-group': KaiSettingsGroupElement;
1818
1971
  'kai-skeleton': KaiSkeletonElement;
1819
1972
  'kai-skills': KaiSkillsElement;
1973
+ 'kai-slider': KaiSliderElement;
1820
1974
  'kai-source': KaiSourceElement;
1821
1975
  'kai-sources': KaiSourcesElement;
1822
1976
  'kai-status': KaiStatusElement;
@@ -1862,6 +2016,8 @@ declare module 'react' {
1862
2016
  'kai-cards': KaiElementJsxProps;
1863
2017
  'kai-chain-of-thought': KaiElementJsxProps;
1864
2018
  'kai-chat': KaiElementJsxProps;
2019
+ 'kai-checkbox': KaiElementJsxProps;
2020
+ 'kai-checkbox-group': KaiElementJsxProps;
1865
2021
  'kai-checkpoint': KaiElementJsxProps;
1866
2022
  'kai-choice': KaiElementJsxProps;
1867
2023
  'kai-coachmark': KaiElementJsxProps;
@@ -1897,11 +2053,13 @@ declare module 'react' {
1897
2053
  'kai-nav': KaiElementJsxProps;
1898
2054
  'kai-notice': KaiElementJsxProps;
1899
2055
  'kai-pane': KaiElementJsxProps;
2056
+ 'kai-pane-grid': KaiElementJsxProps;
1900
2057
  'kai-pane-group': KaiElementJsxProps;
1901
2058
  'kai-popover': KaiElementJsxProps;
1902
2059
  'kai-progress-bar': KaiElementJsxProps;
1903
2060
  'kai-prompt-dock': KaiElementJsxProps;
1904
2061
  'kai-prompt-input': KaiElementJsxProps;
2062
+ 'kai-radio-group': KaiElementJsxProps;
1905
2063
  'kai-reasoning': KaiElementJsxProps;
1906
2064
  'kai-remote': KaiElementJsxProps;
1907
2065
  'kai-resizable': KaiElementJsxProps;
@@ -1913,11 +2071,13 @@ declare module 'react' {
1913
2071
  'kai-scroll-button': KaiElementJsxProps;
1914
2072
  'kai-search': KaiElementJsxProps;
1915
2073
  'kai-segmented': KaiElementJsxProps;
2074
+ 'kai-select': KaiElementJsxProps;
1916
2075
  'kai-separator': KaiElementJsxProps;
1917
2076
  'kai-setting-item': KaiElementJsxProps;
1918
2077
  'kai-settings-group': KaiElementJsxProps;
1919
2078
  'kai-skeleton': KaiElementJsxProps;
1920
2079
  'kai-skills': KaiElementJsxProps;
2080
+ 'kai-slider': KaiElementJsxProps;
1921
2081
  'kai-source': KaiElementJsxProps;
1922
2082
  'kai-sources': KaiElementJsxProps;
1923
2083
  'kai-status': KaiElementJsxProps;
@@ -1995,7 +2155,7 @@ export interface KaiArtifactElementProps {
1995
2155
  export interface KaiAttachmentsElementProps {
1996
2156
  /** Color mode (`auto` follows prefers-color-scheme). */
1997
2157
  theme?: "light" | "dark" | "auto";
1998
- /** The attachments to render. Omit (or pass an empty array) for the empty state, which shows `emptyText` if set and nothing otherwise. Set as a JS property (array). */
2158
+ /** The attachments to render. Omit (or pass an empty array) for the empty state, which shows `emptyText` if set and nothing otherwise. Set as a JS property (array). Each item's `url` must be a `data:` URI or an https URL, never `URL.createObjectURL`: a `blob:` URL previews here but the wire encoders (`toOpenAIMessages`/`toAnthropicMessages`) refuse it. */
1999
2159
  items?: { id: string; type: "file" | "source-document"; filename?: string; mediaType?: string; url?: string; title?: string }[];
2000
2160
  /** Layout: `grid` = visual tiles, `inline` = icon + label chips, `list` = rows. */
2001
2161
  variant?: "grid" | "inline" | "list";
@@ -2124,7 +2284,7 @@ export interface KaiCardsElementProps {
2124
2284
  /** JSON Schemas for the card types this app renders, keyed by envelope type. The companion of `types`, which says what DRAWS a card while this says what a VALID one looks like. An OBJECT, so it is a JS property only: `el.schemas = { 'pricing-table': pricingSchema }`, never an attribute. `createCardRegistry(...).validationSchemas` is exactly this shape. Without it the kit validates its own seven built-ins and leaves your own card type, the one your app actually cares about, as the only unchecked thing on screen. A schema here WINS over a built-in of the same name, matching `mergeCardTags`, where your entry is spread over ours. Typed `Record<string, object>` rather than `Record<string, JsonSchema>` deliberately: an imported `.json` schema widens `"type"` to `string`, and an authored one carries `$schema`/`title`/`description`/`additionalProperties`, so the tighter type would reject both of the normal ways to supply one. See `CardSchemaMap` in components/card-renderer.tsx. */
2125
2285
  schemas?: Record<string, object>;
2126
2286
  /** Optional CardPolicy handling child events. Property: `el.policy`. */
2127
- policy?: { onSubmit?: (cardId: string, data: unknown) => void; onAction?: (cardId: string, action: string, payload?: unknown) => void; onSendPrompt?: (text: string, opts: { mode: "compose" | "send"; context?: unknown; }) => void; onOpen?: (url: string, target: "tab" | "artifact") => void; onState?: (cardId: string, patch: unknown) => void; onDismiss?: (cardId: string) => void; onReopen?: (cardId: string) => void; onError?: (cardId: string, message: string) => void; maxSendPromptMode?: "compose" | "send" };
2287
+ policy?: { onSubmit?: ((cardId: string, data: unknown) => void); onAction?: ((cardId: string, action: string, payload?: unknown) => void); onSendPrompt?: ((text: string, opts: { mode: "compose" | "send"; context?: unknown; }) => void); onOpen?: ((url: string, target: "tab" | "artifact") => void); onState?: ((cardId: string, patch: unknown) => void); onDismiss?: ((cardId: string) => void); onReopen?: ((cardId: string) => void); onError?: ((cardId: string, message: string) => void); maxSendPromptMode?: "compose" | "send" };
2128
2288
  /** Validate each envelope's `data` against the schema for its type before rendering it, using a built-in's own schema or yours from `schemas`. Default `true`; set `validate-cards="false"` (or `el.validateCards = false`) to opt out. A hard failure (wrong type, a missing required field) renders a diagnostic naming the field instead of the card; a soft failure (bounds) renders the card unchanged. Both emit a contract `error` event. On in production too: a model emitting a bad shape is a production failure mode, so stripping the check there would hide it from exactly the person who needs to see it. */
2129
2289
  validateCards?: boolean;
2130
2290
  }
@@ -2163,6 +2323,10 @@ export interface KaiChatElementProps {
2163
2323
  codeTheme?: string;
2164
2324
  /** Enable Shiki syntax highlighting in code blocks. Turn off to render plain `<pre>` blocks (lighter, no highlighter load). Default true. */
2165
2325
  codeHighlight?: boolean;
2326
+ /** How `reasoning` parts render across the thread. `'full'` (default) is the current collapsible-disclosure behavior; `'compact'` shows only a shimmer loader while a reasoning part streams and nothing once it settles (no expandable detail); `'off'` renders reasoning parts not at all. Forwarded to every `MessageBody` as `reasoningMode`. */
2327
+ reasoning?: "full" | "compact" | "off";
2328
+ /** Seeds the reasoning disclosure open AND keeps it tracking the stream (open while streaming, closes when it settles): the pre-Task-19f `full` behavior. Default false/absent: the panel starts closed (just the "Thinking" shimmer chip) and only opens on click, the current default (owner ruling, 2026-08-26). Meaningless when `reasoning` is `'compact'` or `'off'`. Forwarded to every `MessageBody` as `reasoningDefaultOpen`. */
2329
+ reasoningOpen?: boolean;
2166
2330
  /** Optional header title shown on the left of the header. */
2167
2331
  chatTitle?: string;
2168
2332
  /** Optional model list. When set (>1 model) a ModelSwitcher is shown in the header and a `kai-model-change` event fires on selection. */
@@ -2189,6 +2353,8 @@ export interface KaiChatElementProps {
2189
2353
  composerActions?: boolean;
2190
2354
  /** INJECT: footer row below the composer (disclaimers, token meter, …). */
2191
2355
  footer?: boolean;
2356
+ /** When `false`, hides the built-in paperclip attach button. Defaults to `true` (undeclared keeps today's behavior: attach visible), matching `DefaultPromptInput`'s own default: only an explicit `false` hides it. */
2357
+ attach?: boolean;
2192
2358
  /** Show a web-search (Globe) button in the input toolbar; calls `onWebSearch`. */
2193
2359
  webSearch?: boolean;
2194
2360
  /** Show a Voice (Mic) button in the input toolbar; fires a `voice` event. */
@@ -2209,6 +2375,42 @@ export interface KaiChatElementProps {
2209
2375
  cardSchemas?: Record<string, object>;
2210
2376
  }
2211
2377
 
2378
+ export interface KaiCheckboxElementProps {
2379
+ /** Color mode (`auto` follows prefers-color-scheme). */
2380
+ theme?: "light" | "dark" | "auto";
2381
+ /** Controlled checked state. Settable and reflected to the `checked` attribute. `el.checked = true` (or `<kai-checkbox checked>`) drives it; ticking the box updates it and fires `kai-change`. Read `el.checked` for live state. */
2382
+ checked?: boolean;
2383
+ /** Initial checked state on mount (uncontrolled seed). Bare attribute (`<kai-checkbox default-checked>`) turns it on. */
2384
+ defaultChecked?: boolean;
2385
+ /** The mixed state, for a parent box whose children are partly ticked. Visual plus an accessibility hint: the box still reports `checked === false`. */
2386
+ indeterminate?: boolean;
2387
+ /** Disable interaction. */
2388
+ disabled?: boolean;
2389
+ /** Set the native `required` attribute, and nothing more. Whether an unticked box is an error is the application's rule, not the kit's. */
2390
+ required?: boolean;
2391
+ /** Accessible label. The visible text beside the box is the consumer's to render. */
2392
+ label?: string;
2393
+ /** Form-control name (paired with `value`). */
2394
+ name?: string;
2395
+ /** Submitted value when checked (paired with `name`). Defaults to `'on'`. */
2396
+ value?: string;
2397
+ }
2398
+
2399
+ export interface KaiCheckboxGroupElementProps {
2400
+ /** Color mode (`auto` follows prefers-color-scheme). */
2401
+ theme?: "light" | "dark" | "auto";
2402
+ /** The choices, top to bottom. Set as a JS PROPERTY (array), never an attribute. Rendered in full: the kit never truncates, re-orders or de-duplicates them. */
2403
+ options: { value: string; label: string; description?: undefined | string; disabled?: undefined | boolean }[];
2404
+ /** The FIRST selected value. Settable and reflected to the `value` attribute, so `:host([value])` and `el.value` see live state, and a seed can be written in markup. Writing it makes that the whole selection; to read or drive the rest, use `el.values`. */
2405
+ value?: string;
2406
+ /** The shared form-control name every box carries, so `FormData.getAll(name)` reads the whole selection back under one key. NO DEFAULT, unlike `<kai-radio-group>`. A radio set needs a shared `name` for the browser to make it exclusive and arrow-navigable, so one is generated when none is given; checkboxes are independent controls and behave correctly with no name at all. Generating one here would submit the selection under a random key, which is worse than submitting nothing. The element is NOT form-associated (no `ElementInternals`, no `setFormValue()`), the same known gap `<kai-input>` records: the boxes live in a shadow root, so a surrounding `<form>` collects nothing from them whether or not `name` is set. Read `el.values`. The name still lands on every inner input, so it is right the day form association arrives. */
2407
+ name?: string;
2408
+ /** Disable every row. Individual rows carry their own `disabled`. */
2409
+ disabled?: boolean;
2410
+ /** Accessible name for the group. */
2411
+ label?: string;
2412
+ }
2413
+
2212
2414
  export interface KaiCheckpointElementProps {
2213
2415
  /** Color mode (`auto` follows prefers-color-scheme). */
2214
2416
  theme?: "light" | "dark" | "auto";
@@ -2359,9 +2561,9 @@ export interface KaiContextElementProps {
2359
2561
  export interface KaiConversationItemElementProps {
2360
2562
  /** Color mode (`auto` follows prefers-color-scheme). */
2361
2563
  theme?: "light" | "dark" | "auto";
2362
- /** The row's identity, handed to the container's selection contract. In the element this is the `conversation-id` attribute (host `id` is the fallback). */
2564
+ /** The row's identity: the `conversation-id` attribute (host `id` is the fallback). Inside `<kai-conversations>` it is handed to the container's selection contract (`kai-conversation-select`); standalone it is the `id` in this element's own `kai-select` detail. */
2363
2565
  conversationId?: string;
2364
- /** Selected state. Reflected as `aria-current` on the row body and a `data-active` styling hook on the row; the container drives it from its `activeId`. */
2566
+ /** Selected state. Reflected as `aria-current` on the row body and a `data-active` styling hook on the row; inside a container the container drives it from its `activeId`, standalone you set it yourself. */
2365
2567
  active?: boolean;
2366
2568
  /** Dense single-line row padding. */
2367
2569
  compact?: boolean;
@@ -2414,6 +2616,8 @@ export interface KaiDockElementProps {
2414
2616
  unread?: boolean;
2415
2617
  /** Disable the launcher; `show()` and `toggle()` are gated on it. */
2416
2618
  disabled?: boolean;
2619
+ /** Suppress the dock's own built-in mobile close X. Set this when your slotted panel content supplies its own close affordance (e.g. a `<kai-chat slot="header-end">` close button), otherwise the two stack. TRADEOFF: the mobile panel reserves a padding band above its content so the built-in X never paints over slotted content; that band stays reserved unless you set this true, so only set it once your own control is actually in place. Attribute: `hide-close`. */
2620
+ hideClose?: boolean;
2417
2621
  /** Where focus lands on open: `content` (default, the first element you slotted), `panel`, or `none`. Attribute: `focus-on-open`. */
2418
2622
  focusOnOpen?: "content" | "panel" | "none";
2419
2623
  }
@@ -2519,7 +2723,7 @@ export interface KaiFormElementProps {
2519
2723
  /** Color mode (`auto` follows prefers-color-scheme). */
2520
2724
  theme?: "light" | "dark" | "auto";
2521
2725
  /** The form definition: a JSON Schema (`type:'object'`) + `x-kai-*` UI hints (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { type:'object', properties:{…} }`. Import the `FormDefinition` type from `@kitn.ai/ui` for the full shape. It IS self-referential (`FormField.properties` is another `FormField` map), and the generated `element-types.d.ts` inlines every named type, so the shipped declaration bottoms out in a `Record<string, unknown>` placeholder one level down rather than carrying the recursion. That is why `FormDefinition` is a `type` alias: an interface gets no implicit index signature, so it would not be assignable to that placeholder. */
2522
- data?: { type: "object"; title?: string; description?: string; required?: string[]; properties: Record<string, { type: "string" | "number" | "integer" | "boolean" | "array" | "object"; title?: string; description?: string; default?: unknown; enum?: unknown[]; format?: "email" | "uri" | "url" | "date" | "date-time" | "time"; minimum?: number; maximum?: number; minLength?: number; maxLength?: number; pattern?: string; minItems?: number; maxItems?: number; items?: Record<string, unknown> | { enum: unknown[] }; properties?: Record<string, Record<string, unknown>>; required?: string[]; readOnly?: boolean; "x-kai-widget"?: "textarea" | "slider" | "rating" | "radio" | "select" | "checkbox" | "password" | "switch"; "x-kai-placeholder"?: string; "x-kai-step"?: number }>; "x-kai-order"?: string[]; "x-kai-inlineMax"?: number; "x-kai-submitLabel"?: string; "x-kai-dismissible"?: boolean; "x-kai-actions"?: { id: string; label: string; variant?: "default" | "ghost" | "outline" }[] };
2726
+ data?: { type: "object"; title?: string; description?: string; required?: string[]; properties: Record<string, { type: "string" | "number" | "integer" | "boolean" | "array" | "object"; title?: string; description?: string; default?: unknown; enum?: unknown[]; format?: "email" | "uri" | "url" | "date" | "date-time" | "time"; minimum?: number; maximum?: number; minLength?: number; maxLength?: number; pattern?: string; minItems?: number; maxItems?: number; items?: Record<string, unknown> | { enum: unknown[] }; properties?: Record<string, Record<string, unknown>>; required?: string[]; readOnly?: boolean; "x-kai-widget"?: "textarea" | "slider" | "rating" | "radio" | "select" | "checkbox" | "password" | "switch"; "x-kai-placeholder"?: string; "x-kai-step"?: number; "x-kai-format"?: "tel" | "ssn" | "credit-card" | "custom"; "x-kai-mask"?: string; "x-kai-mask-guide"?: string }>; "x-kai-order"?: string[]; "x-kai-inlineMax"?: number; "x-kai-submitLabel"?: string; "x-kai-dismissible"?: boolean; "x-kai-actions"?: { id: string; label: string; variant?: "default" | "ghost" | "outline" }[] };
2523
2727
  /** Stable card id correlating every emitted CardEvent. Attribute: `card-id`. */
2524
2728
  cardId?: string;
2525
2729
  /** Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. */
@@ -2578,7 +2782,7 @@ export interface KaiInputElementProps {
2578
2782
  theme?: "light" | "dark" | "auto";
2579
2783
  /** Native input type: `text` (default) · `email` · `url` · `search` · `tel` · `password` · `number`. Single-line only. */
2580
2784
  type?: string;
2581
- /** Controlled value. Settable and reflected to the `value` attribute. `el.value = 'hi'` drives it (no event); typing updates it and fires `kai-input`. Read `el.value` for live state. */
2785
+ /** Controlled value, and always the CANONICAL one when a mask is active: digits for `tel` / `ssn` / `credit-card`, the formatted text for `custom`. Settable and reflected to the `value` attribute. `el.value = '5551234567'` drives it (no event) and is re-fitted to the mask on the way in, so the field shows `555-123-4567`. Read `el.value` for live state; the formatted text rides along on every `kai-input` / `kai-change` detail as `formattedValue`. */
2582
2786
  value?: string;
2583
2787
  /** Placeholder shown when empty. */
2584
2788
  placeholder?: string;
@@ -2604,6 +2808,16 @@ export interface KaiInputElementProps {
2604
2808
  autocomplete?: string;
2605
2809
  /** Virtual-keyboard hint forwarded to the inner input (e.g. `numeric`, `email`). */
2606
2810
  inputmode?: string;
2811
+ /** Mask pattern: `#` a digit, `@` a letter or digit, `*` an obscurable letter or digit, and every other character a positional literal (`@@@-####` → `CHG-4821`). The literal `default` is the opt-in sentinel: it resolves to the default format of `semantic` (`tel` → `###-###-####`). A bare `semantic` never starts masking on its own, so an opt-in token is what turns tier 2 on. */
2812
+ format?: string;
2813
+ /** Placeholder guide shown at unfilled positions, aligned position for position with `format`: `mm/dd/yyyy` against `##/##/####`. Spaces are a valid guide character, so a guide of blanks and separators is how a phone field shows its shape without showing letters. Without a guide the field shows only up to the last typed character. A guide is a visual aid, never an accessible name: keep the `hint` text as well. */
2814
+ guide?: string;
2815
+ /** Semantic field type: `tel` · `ssn` · `credit-card` · `custom`. On its own it sets `inputmode` / `autocomplete` / `spellcheck` / `autocorrect` / `autocapitalize` and decides the canonical value; it never starts masking by itself. */
2816
+ semantic?: "credit-card" | "custom" | "ssn" | "tel";
2817
+ /** Case folding applied to typed and pasted text: `preserve` (default) · `upper` · `lower`. Attribute: `case-mode`. */
2818
+ caseMode?: "preserve" | "upper" | "lower";
2819
+ /** What a copy or cut of a masked field puts on the clipboard: `canonical` (default) · `formatted` · `obscured` · `blocked`. Attribute: `copy-policy`. */
2820
+ copyPolicy?: "formatted" | "canonical" | "obscured" | "blocked";
2607
2821
  }
2608
2822
 
2609
2823
  export interface KaiKbdElementProps {
@@ -2762,6 +2976,21 @@ export interface KaiPaneElementProps {
2762
2976
  status?: { tone: "working" | "idle" | "done" | "error" | "blocked"; label?: string; pulse?: boolean };
2763
2977
  }
2764
2978
 
2979
+ export interface KaiPaneGridElementProps {
2980
+ /** Color mode (`auto` follows prefers-color-scheme). */
2981
+ theme?: "light" | "dark" | "auto";
2982
+ /** Minimum width of every pane, in px, before columns drop / the grid scrolls. Defaults to `280`. Attribute: `min-pane-width`. */
2983
+ minPaneWidth?: number;
2984
+ /** Minimum height of every pane, in px, before the grid scrolls vertically. Defaults to `200`. Attribute: `min-pane-height`. */
2985
+ minPaneHeight?: number;
2986
+ /** Column cap when the container is wide (default `3`). Attribute: `max-columns`. */
2987
+ maxColumns?: number;
2988
+ /** Gap between panes, any CSS length. Defaults to the kit gap (`var(--kai-pane-grid-gap, 0.5rem)`). Attribute: `gap`. */
2989
+ gap?: string;
2990
+ /** When set to a valid child index, render ONLY that pane full-bleed: a simple maximize hook the consumer drives (pair it with `<kai-pane>`'s `kai-maximize` event). Clear it (or point out of range) for the full tiled grid. Attribute: `maximized-index`. */
2991
+ maximizedIndex?: number | null;
2992
+ }
2993
+
2765
2994
  export interface KaiPaneGroupElementProps {
2766
2995
  /** Color mode (`auto` follows prefers-color-scheme). */
2767
2996
  theme?: "light" | "dark" | "auto";
@@ -2835,7 +3064,7 @@ export interface KaiPromptInputElementProps {
2835
3064
  submit?: "always" | "auto";
2836
3065
  /** When `false`, hides the built-in paperclip attach button even though the element otherwise supports attachments. Use this when a `+` menu in `toolbar-start` already exposes "Add files", to avoid a duplicate control. Defaults to `true`. */
2837
3066
  attach?: boolean;
2838
- /** Attachments to seed the input with (so a consumer can pre-populate staged files without an upload). Set as a JS property; the element then manages its own attachment state from there (add via the paperclip, remove per chip). */
3067
+ /** Attachments to seed the input with (so a consumer can pre-populate staged files without an upload). Set as a JS property; the element then manages its own attachment state from there (add via the paperclip, remove per chip). Each item's `url` must be a `data:` URI or an https URL, never `URL.createObjectURL`: a `blob:` URL previews perfectly and is meaningless outside this tab, so `toOpenAIMessages`/`toAnthropicMessages` refuse it. (The built-in paperclip already stages files as `data:` URIs.) */
2839
3068
  attachments?: { id: string; type: "file" | "source-document"; filename?: string; mediaType?: string; url?: string; title?: string }[];
2840
3069
  /** Rich entity triggers. Each `{ char, kind, items }` opens a caret-anchored menu that inserts an atomic pill. Convention: `/` → skills, `@` → agents (plugins are the grouping/provenance of those items). Set as a JS property. */
2841
3070
  triggers?: { char: string; kind: string; items?: { id: string; label: string; icon?: string; description?: string; group?: string; kind?: string; promptText?: string; data?: Record<string, unknown> }[] }[];
@@ -2843,6 +3072,21 @@ export interface KaiPromptInputElementProps {
2843
3072
  kindIcons?: Record<string, string>;
2844
3073
  }
2845
3074
 
3075
+ export interface KaiRadioGroupElementProps {
3076
+ /** Color mode (`auto` follows prefers-color-scheme). */
3077
+ theme?: "light" | "dark" | "auto";
3078
+ /** The choices, top to bottom. Set as a JS PROPERTY (array), never an attribute. */
3079
+ options: { value: string; label: string; description?: undefined | string; disabled?: undefined | boolean }[];
3080
+ /** Controlled selected `value`. Settable and reflected to the `value` attribute. `el.value = 'degraded'` drives it; choosing a row updates it and fires `kai-change`. Read `el.value` for live state. */
3081
+ value?: string;
3082
+ /** Shared form-control name for every radio in the group. Defaults to a generated id, so the group is exclusive and keyboard-navigable even when nothing is submitted. */
3083
+ name?: string;
3084
+ /** Disable every row. Individual rows carry their own `disabled`. */
3085
+ disabled?: boolean;
3086
+ /** Accessible name for the group. */
3087
+ label?: string;
3088
+ }
3089
+
2846
3090
  export interface KaiReasoningElementProps {
2847
3091
  /** Color mode (`auto` follows prefers-color-scheme). */
2848
3092
  theme?: "light" | "dark" | "auto";
@@ -2964,6 +3208,10 @@ export interface KaiScrollButtonElementProps {
2964
3208
  variant?: "outline" | "ghost" | "default";
2965
3209
  /** Button size token. Defaults to `'icon'` (square). */
2966
3210
  size?: "sm" | "md" | "lg" | "icon" | "icon-sm";
3211
+ /** The button's accessible name. It is announced whether or not the label is visible, so the text is always localisable. Defaults to `'Scroll to bottom'`. */
3212
+ label?: string;
3213
+ /** Also render `label` visibly beside the icon. Defaults to `false`, which is the icon-only button. When the text is visible it IS the accessible name, so nothing gets announced twice. */
3214
+ showLabel?: boolean;
2967
3215
  }
2968
3216
 
2969
3217
  export interface KaiSearchElementProps {
@@ -2994,6 +3242,29 @@ export interface KaiSegmentedElementProps {
2994
3242
  size?: "sm" | "md";
2995
3243
  }
2996
3244
 
3245
+ export interface KaiSelectElementProps {
3246
+ /** Color mode (`auto` follows prefers-color-scheme). */
3247
+ theme?: "light" | "dark" | "auto";
3248
+ /** The choices, in display order. Set as a JS PROPERTY (array), never an attribute. Rendered in full: the kit never truncates, re-orders or de-duplicates them. */
3249
+ options: { value: string; label?: undefined | string; disabled?: undefined | boolean }[];
3250
+ /** Controlled selected value. Settable and reflected to the `value` attribute. `el.value = 'high'` drives it; choosing an option updates it and fires `kai-change`. Read `el.value` for live state; for a `multiple` select read `el.values` instead. */
3251
+ value?: string;
3252
+ /** Text for a leading, disabled, empty option: the "nothing chosen yet" row. Omitted means no such row at all; there is no default wording, because inventing one would put words in your UI. */
3253
+ placeholder?: string;
3254
+ /** Allow more than one selection. Turns the control into the platform's list box, so the kit's chevron is not drawn. */
3255
+ multiple?: boolean;
3256
+ /** Force the invalid (destructive-border) state. */
3257
+ invalid?: boolean;
3258
+ /** Disable interaction. */
3259
+ disabled?: boolean;
3260
+ /** Set the native `required` attribute, and nothing more. Whether an empty select is an error is the application's rule, not the kit's. */
3261
+ required?: boolean;
3262
+ /** Accessible label for the control. */
3263
+ label?: string;
3264
+ /** Form-control name, for a native form submit. */
3265
+ name?: string;
3266
+ }
3267
+
2997
3268
  export interface KaiSeparatorElementProps {
2998
3269
  /** Color mode (`auto` follows prefers-color-scheme). */
2999
3270
  theme?: "light" | "dark" | "auto";
@@ -3039,6 +3310,27 @@ export interface KaiSkillsElementProps {
3039
3310
  skills?: { id: string; name: string }[];
3040
3311
  }
3041
3312
 
3313
+ export interface KaiSliderElementProps {
3314
+ /** Color mode (`auto` follows prefers-color-scheme). */
3315
+ theme?: "light" | "dark" | "auto";
3316
+ /** Lowest selectable value. Required: a range with no bounds is a guess, and the guess belongs to whoever knows what the number means. */
3317
+ min?: number;
3318
+ /** Highest selectable value. Required, for the same reason as `min`. */
3319
+ max?: number;
3320
+ /** Granularity. Omitted means the native default of 1; `any` means continuous. */
3321
+ step?: number | "any";
3322
+ /** Controlled value. Settable and reflected to the `value` attribute. `el.value = 40` drives it; dragging updates it and fires `kai-input` per step, `kai-change` on release. Read `el.value` for live state. */
3323
+ value?: number;
3324
+ /** Disable interaction. */
3325
+ disabled?: boolean;
3326
+ /** Accessible label for the slider. */
3327
+ label?: string;
3328
+ /** Form-control name, for a native form submit. */
3329
+ name?: string;
3330
+ /** Show the current value beside the track. Off by default. Two ways in, because one of them is not a scalar. As a bare ATTRIBUTE (`<kai-slider value-label>`) it renders the raw number. As a JS PROPERTY it also accepts a formatter function (`el.valueLabel = (v) => v + '%'`), for a slider that is not counting bare numbers. A function cannot survive an attribute, so that half is property-only. The readout is hidden from assistive tech: the slider already reports the same number, and an exposed copy would be announced twice. */
3331
+ valueLabel?: boolean | ((value: number) => string);
3332
+ }
3333
+
3042
3334
  export interface KaiSourceElementProps {
3043
3335
  /** Color mode (`auto` follows prefers-color-scheme). */
3044
3336
  theme?: "light" | "dark" | "auto";
@@ -3202,7 +3494,7 @@ export interface KaiThreadElementProps {
3202
3494
  export interface KaiToastRegionElementProps {
3203
3495
  /** Color mode (`auto` follows prefers-color-scheme). */
3204
3496
  theme?: "light" | "dark" | "auto";
3205
- /** The toasts to render. Newest is shown on top. Set as a JS property (array); pass a new array reference to update. Omit for an empty region, which is the normal resting state and how the imperative `toast()` API starts. */
3497
+ /** The toasts to render. Newest is shown on top. Set as a JS property (array); pass a new array reference to update. Omit for an empty region, which is the normal resting state and how the imperative `toast()` API starts. Note the handover: the first `toast()` call ADOPTS a region you placed in markup (no second region mounts) and binds the imperative store to this property, replacing any array you set. Drive a region as data OR via `toast()`, not both at once. */
3206
3498
  toasts?: { id: string; message: string; variant?: "neutral" | "success" | "warning" | "error" | "info"; appearance?: "pill" | "card"; inverse?: boolean; description?: string; action?: { label: string; onAction: () => void | false }; duration?: number; dismissible?: boolean; target?: HTMLElement }[];
3207
3499
  /** Stack anchor: `'top-center'` (default), `'top-right'`, `'bottom-center'`, … */
3208
3500
  position?: "top-center" | "top-right" | "top-left" | "bottom-center" | "bottom-right" | "bottom-left";
@@ -3375,6 +3667,16 @@ export interface KaiChatElementEvents {
3375
3667
  onKaiWebSearch?: (event: CustomEvent<Record<string, never>>) => void;
3376
3668
  }
3377
3669
 
3670
+ export interface KaiCheckboxElementEvents {
3671
+ /** The box was ticked or unticked. */
3672
+ onKaiChange?: (event: CustomEvent<{ checked: boolean }>) => void;
3673
+ }
3674
+
3675
+ export interface KaiCheckboxGroupElementEvents {
3676
+ /** A row was ticked or unticked. `values` is the whole selection after the change, which is what a multi-select control needs; `value` is the first of them (empty when nothing is selected). Both are always present, so neither shape silently loses the other. This is `<kai-select>`'s detail, deliberately. */
3677
+ onKaiChange?: (event: CustomEvent<{ value: string; values: string[] }>) => void;
3678
+ }
3679
+
3378
3680
  export interface KaiCheckpointElementEvents {
3379
3681
  /** The checkpoint was clicked. */
3380
3682
  onKaiSelect?: (event: CustomEvent) => void;
@@ -3423,7 +3725,7 @@ export interface KaiComposerElementEvents {
3423
3725
  onKaiEntityRemove?: (event: CustomEvent<{ entity: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown> } }>) => void;
3424
3726
  /** The composer gained focus. `focus`/`blur` are NOT composed natively, so they don't escape the shadow root; these re-expose them on the host. (For `keydown`/`paste`/`focusin`/`focusout`, listen NATIVELY on `<kai-composer>`: they're composed and already cross the shadow boundary.) */
3425
3727
  onKaiFocus?: (event: CustomEvent<{ originalEvent: FocusEvent }>) => void;
3426
- /** The user submitted the composer (Enter or programmatic submit). */
3728
+ /** The user submitted the composer (Enter or programmatic submit). Note the detail carries no `attachments`; `<kai-composer>` is the bare editing surface: no send button, toolbar, or attachments. For a drop-in composer row with all three, reach for `<kai-prompt-input>`, which is built on this. */
3427
3729
  onKaiSubmit?: (event: CustomEvent<{ doc: ({ type: "text"; text: string } | { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown> } })[]; text: string; entities: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown> }[] }>) => void;
3428
3730
  /** A trigger character was detected at the caret (e.g. `/` or `@`). */
3429
3731
  onKaiTrigger?: (event: CustomEvent<{ char: string; query: string; rect: DOMRect }>) => void;
@@ -3443,7 +3745,8 @@ export interface KaiContextElementEvents {
3443
3745
  }
3444
3746
 
3445
3747
  export interface KaiConversationItemElementEvents {
3446
-
3748
+ /** STANDALONE activation only: the row was activated (click, Enter or Space on its body) while the item is NOT a direct child of `<kai-conversations>`. `id` is the row's identity: the `conversation-id` attribute, else the host `id`. Inside a container this never fires: activation surfaces once, as `kai-conversation-select` on the container. */
3749
+ onKaiSelect?: (event: CustomEvent<{ id: string }>) => void;
3447
3750
  }
3448
3751
 
3449
3752
  export interface KaiConversationsElementEvents {
@@ -3527,10 +3830,12 @@ export interface KaiImageElementEvents {
3527
3830
  }
3528
3831
 
3529
3832
  export interface KaiInputElementEvents {
3530
- /** The value was committed (blur). */
3531
- onKaiChange?: (event: CustomEvent<{ value: string }>) => void;
3532
- /** The value changed per keystroke. */
3533
- onKaiInput?: (event: CustomEvent<{ value: string }>) => void;
3833
+ /** The value was committed (blur). Same detail shape as `kai-input`. */
3834
+ onKaiChange?: (event: CustomEvent<{ value: string; formattedValue: string }>) => void;
3835
+ /** The value changed per keystroke. `value` is the canonical value (what a backend wants); `formattedValue` is the text on screen. With no mask the two are equal. */
3836
+ onKaiInput?: (event: CustomEvent<{ value: string; formattedValue: string }>) => void;
3837
+ /** A mask refused, or partly refused, some content. The reasons are `full` (no free position left), `wrong-class` (a letter into a digit position), `over-capacity` (a paste longer than the mask holds; what fits was kept), and `format-change-clipped` (the `format` changed under a value that no longer fits). `data` is the content that was refused. The first three are USER-INPUT errors, and are the ones worth announcing in a polite live region. `format-change-clipped` is not one: it follows the app changing its own configuration, so it reports and nothing more. None of the four touches validity, so `invalid` and `error` stay the consumer decision. */
3838
+ onKaiInputRejected?: (event: CustomEvent<{ reason: "full" | "wrong-class" | "over-capacity" | "format-change-clipped"; data: string }>) => void;
3534
3839
  }
3535
3840
 
3536
3841
  export interface KaiKbdElementEvents {
@@ -3593,6 +3898,10 @@ export interface KaiPaneElementEvents {
3593
3898
  onKaiSplit?: (event: CustomEvent) => void;
3594
3899
  }
3595
3900
 
3901
+ export interface KaiPaneGridElementEvents {
3902
+
3903
+ }
3904
+
3596
3905
  export interface KaiPaneGroupElementEvents {
3597
3906
  /** A tab was selected (click, Enter/Space, or arrow-key move). `detail.id` is the tab's id. */
3598
3907
  onKaiTabChange?: (event: CustomEvent<{ id: string }>) => void;
@@ -3620,7 +3929,7 @@ export interface KaiPromptInputElementEvents {
3620
3929
  onKaiAttachmentsChange?: (event: CustomEvent<{ attachments: { id: string; type: "file" | "source-document"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[] }>) => void;
3621
3930
  /** The Stop button was clicked while `stoppable` and `loading` are both true. */
3622
3931
  onKaiStop?: (event: CustomEvent<Record<string, never>>) => void;
3623
- /** The user submitted the prompt (Enter or send button). `value` is the flattened text (back-compat); `doc` is the structured document and `entities` the inserted pills (skills/agents) for downstream expansion. */
3932
+ /** The user submitted the prompt (Enter or send button). `value` is the flattened text (back-compat); `doc` is the structured document and `entities` the inserted pills (skills/agents) for downstream expansion. `<kai-prompt-input>` is the batteries-included composer row (send button, toolbar, attachment staging) built on `<kai-composer>`, the bare editor. */
3624
3933
  onKaiSubmit?: (event: CustomEvent<{ value: string; doc: ({ type: "text"; text: string } | { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown> } })[]; entities: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown> }[]; attachments: { id: string; type: "file" | "source-document"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[] }>) => void;
3625
3934
  /** A suggestion was clicked while `suggestion-mode="fill"`. */
3626
3935
  onKaiSuggestionClick?: (event: CustomEvent<{ value: string }>) => void;
@@ -3634,6 +3943,11 @@ export interface KaiPromptInputElementEvents {
3634
3943
  onKaiWebSearch?: (event: CustomEvent<Record<string, never>>) => void;
3635
3944
  }
3636
3945
 
3946
+ export interface KaiRadioGroupElementEvents {
3947
+ /** A row was chosen. */
3948
+ onKaiChange?: (event: CustomEvent<{ value: string }>) => void;
3949
+ }
3950
+
3637
3951
  export interface KaiReasoningElementEvents {
3638
3952
  /** The reasoning block expanded or collapsed (via the trigger, streaming auto-open, or a method). */
3639
3953
  onKaiOpenChange?: (event: CustomEvent<{ open: boolean }>) => void;
@@ -3700,6 +4014,11 @@ export interface KaiSegmentedElementEvents {
3700
4014
  onKaiChange?: (event: CustomEvent<{ value: string }>) => void;
3701
4015
  }
3702
4016
 
4017
+ export interface KaiSelectElementEvents {
4018
+ /** A choice was made. `value` is the first selected option (empty when nothing is selected); `values` is every selected option, which is what a `multiple` select needs. Both are always present, so neither shape silently loses the other. */
4019
+ onKaiChange?: (event: CustomEvent<{ value: string; values: string[] }>) => void;
4020
+ }
4021
+
3703
4022
  export interface KaiSeparatorElementEvents {
3704
4023
 
3705
4024
  }
@@ -3720,6 +4039,13 @@ export interface KaiSkillsElementEvents {
3720
4039
 
3721
4040
  }
3722
4041
 
4042
+ export interface KaiSliderElementEvents {
4043
+ /** The value was committed: pointer released, or a key press finished. */
4044
+ onKaiChange?: (event: CustomEvent<{ value: number }>) => void;
4045
+ /** The thumb moved. Fires per step during a drag or a key press. */
4046
+ onKaiInput?: (event: CustomEvent<{ value: number }>) => void;
4047
+ }
4048
+
3723
4049
  export interface KaiSourceElementEvents {
3724
4050
 
3725
4051
  }
@@ -3851,6 +4177,10 @@ declare module 'vue' {
3851
4177
  KaiChainOfThought: KaiVueElement<KaiChainOfThoughtElementProps, KaiChainOfThoughtElementEvents>;
3852
4178
  'kai-chat': KaiVueElement<KaiChatElementProps, KaiChatElementEvents>;
3853
4179
  KaiChat: KaiVueElement<KaiChatElementProps, KaiChatElementEvents>;
4180
+ 'kai-checkbox': KaiVueElement<KaiCheckboxElementProps, KaiCheckboxElementEvents>;
4181
+ KaiCheckbox: KaiVueElement<KaiCheckboxElementProps, KaiCheckboxElementEvents>;
4182
+ 'kai-checkbox-group': KaiVueElement<KaiCheckboxGroupElementProps, KaiCheckboxGroupElementEvents>;
4183
+ KaiCheckboxGroup: KaiVueElement<KaiCheckboxGroupElementProps, KaiCheckboxGroupElementEvents>;
3854
4184
  'kai-checkpoint': KaiVueElement<KaiCheckpointElementProps, KaiCheckpointElementEvents>;
3855
4185
  KaiCheckpoint: KaiVueElement<KaiCheckpointElementProps, KaiCheckpointElementEvents>;
3856
4186
  'kai-choice': KaiVueElement<KaiChoiceElementProps, KaiChoiceElementEvents>;
@@ -3921,6 +4251,8 @@ declare module 'vue' {
3921
4251
  KaiNotice: KaiVueElement<KaiNoticeElementProps, KaiNoticeElementEvents>;
3922
4252
  'kai-pane': KaiVueElement<KaiPaneElementProps, KaiPaneElementEvents>;
3923
4253
  KaiPane: KaiVueElement<KaiPaneElementProps, KaiPaneElementEvents>;
4254
+ 'kai-pane-grid': KaiVueElement<KaiPaneGridElementProps, KaiPaneGridElementEvents>;
4255
+ KaiPaneGrid: KaiVueElement<KaiPaneGridElementProps, KaiPaneGridElementEvents>;
3924
4256
  'kai-pane-group': KaiVueElement<KaiPaneGroupElementProps, KaiPaneGroupElementEvents>;
3925
4257
  KaiPaneGroup: KaiVueElement<KaiPaneGroupElementProps, KaiPaneGroupElementEvents>;
3926
4258
  'kai-popover': KaiVueElement<KaiPopoverElementProps, KaiPopoverElementEvents>;
@@ -3931,6 +4263,8 @@ declare module 'vue' {
3931
4263
  KaiPromptDock: KaiVueElement<KaiPromptDockElementProps, KaiPromptDockElementEvents>;
3932
4264
  'kai-prompt-input': KaiVueElement<KaiPromptInputElementProps, KaiPromptInputElementEvents>;
3933
4265
  KaiPromptInput: KaiVueElement<KaiPromptInputElementProps, KaiPromptInputElementEvents>;
4266
+ 'kai-radio-group': KaiVueElement<KaiRadioGroupElementProps, KaiRadioGroupElementEvents>;
4267
+ KaiRadioGroup: KaiVueElement<KaiRadioGroupElementProps, KaiRadioGroupElementEvents>;
3934
4268
  'kai-reasoning': KaiVueElement<KaiReasoningElementProps, KaiReasoningElementEvents>;
3935
4269
  KaiReasoning: KaiVueElement<KaiReasoningElementProps, KaiReasoningElementEvents>;
3936
4270
  'kai-remote': KaiVueElement<KaiRemoteElementProps, KaiRemoteElementEvents>;
@@ -3953,6 +4287,8 @@ declare module 'vue' {
3953
4287
  KaiSearch: KaiVueElement<KaiSearchElementProps, KaiSearchElementEvents>;
3954
4288
  'kai-segmented': KaiVueElement<KaiSegmentedElementProps, KaiSegmentedElementEvents>;
3955
4289
  KaiSegmented: KaiVueElement<KaiSegmentedElementProps, KaiSegmentedElementEvents>;
4290
+ 'kai-select': KaiVueElement<KaiSelectElementProps, KaiSelectElementEvents>;
4291
+ KaiSelect: KaiVueElement<KaiSelectElementProps, KaiSelectElementEvents>;
3956
4292
  'kai-separator': KaiVueElement<KaiSeparatorElementProps, KaiSeparatorElementEvents>;
3957
4293
  KaiSeparator: KaiVueElement<KaiSeparatorElementProps, KaiSeparatorElementEvents>;
3958
4294
  'kai-setting-item': KaiVueElement<KaiSettingItemElementProps, KaiSettingItemElementEvents>;
@@ -3963,6 +4299,8 @@ declare module 'vue' {
3963
4299
  KaiSkeleton: KaiVueElement<KaiSkeletonElementProps, KaiSkeletonElementEvents>;
3964
4300
  'kai-skills': KaiVueElement<KaiSkillsElementProps, KaiSkillsElementEvents>;
3965
4301
  KaiSkills: KaiVueElement<KaiSkillsElementProps, KaiSkillsElementEvents>;
4302
+ 'kai-slider': KaiVueElement<KaiSliderElementProps, KaiSliderElementEvents>;
4303
+ KaiSlider: KaiVueElement<KaiSliderElementProps, KaiSliderElementEvents>;
3966
4304
  'kai-source': KaiVueElement<KaiSourceElementProps, KaiSourceElementEvents>;
3967
4305
  KaiSource: KaiVueElement<KaiSourceElementProps, KaiSourceElementEvents>;
3968
4306
  'kai-sources': KaiVueElement<KaiSourcesElementProps, KaiSourcesElementEvents>;