@kitn.ai/ui 0.25.2 → 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 (603) hide show
  1. package/README.md +17 -6
  2. package/bin/mcp.js +16 -3
  3. package/bin/route.js +23 -0
  4. package/bin/route.test.js +58 -0
  5. package/dist/{elements/chunks/Icon-b5A8hlHs.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/audio-visualizer-B-79y1Tj.js +1 -0
  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-B9okqG73.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/code-block-CUQ5mtv0.js +1 -0
  30. package/dist/collapsible-CPJbf6FM.js +1 -0
  31. package/dist/components/attachment-types.d.ts +53 -1
  32. package/dist/components/attachments.d.ts +31 -0
  33. package/dist/components/audio-visualizer/fit-scale.d.ts +50 -0
  34. package/dist/components/audio-visualizer/index.d.ts +15 -1
  35. package/dist/components/audio-visualizer/variant-bar.d.ts +24 -1
  36. package/dist/components/card-renderer.d.ts +13 -0
  37. package/dist/components/card.d.ts +4 -0
  38. package/dist/components/chat-thread.d.ts +49 -42
  39. package/dist/components/code-block.d.ts +22 -0
  40. package/dist/components/conversation-item.d.ts +66 -1
  41. package/dist/components/conversation-list.d.ts +77 -0
  42. package/dist/components/form-widgets.d.ts +67 -2
  43. package/dist/components/form.d.ts +89 -0
  44. package/dist/components/message.d.ts +29 -0
  45. package/dist/components/reasoning.d.ts +6 -0
  46. package/dist/components/scroll-button.d.ts +11 -0
  47. package/dist/components/thread.d.ts +5 -0
  48. package/dist/components/toast.d.ts +2 -1
  49. package/dist/components/tool-types.d.ts +9 -0
  50. package/dist/components/voice-input.d.ts +8 -0
  51. package/dist/components/voice-output.d.ts +12 -1
  52. package/dist/components/workspace-shell.d.ts +87 -0
  53. package/dist/composer-CjngLzal.js +106 -0
  54. package/dist/confirm-card-DCx_A4bU.js +1 -0
  55. package/dist/construct-cli.es.js +1169 -0
  56. package/dist/context-BY8V-Nlp.js +1 -0
  57. package/dist/controllable-D43BKmtX.js +1 -0
  58. package/dist/conversation-list-D4lLU_yS.js +1 -0
  59. package/dist/copy-B6DO4PqB.js +1 -0
  60. package/dist/core-AYMC6_lb.js +12 -5874
  61. package/dist/{create-tween-CUzOlaMS.js → create-tween-BPzaefTp.js} +1 -1
  62. package/dist/{create-tween-B5Y4Im8G.js → create-tween-CnMHviKB.js} +1 -1
  63. package/dist/{create-tween-4z1XYLkR.js → create-tween-D1aiGZZh.js} +1 -1
  64. package/dist/{elements/chunks/create-tween-CUrM6D_o.js → create-tween-DUSQUKpr.js} +2 -2
  65. package/dist/css-M7EaDHN_.js +1 -6
  66. package/dist/custom-elements.json +3468 -1927
  67. package/dist/default-input-CucQEOqH.js +1 -0
  68. package/dist/define-CGGX-7Vg.js +1 -0
  69. package/dist/define.d.ts +4 -0
  70. package/dist/define.js +510 -0
  71. package/dist/define.server.d.ts +5 -0
  72. package/dist/define.server.js +506 -0
  73. package/dist/diagnostics/hook.d.ts +81 -0
  74. package/dist/diagnostics/index.d.ts +7 -0
  75. package/dist/diagnostics/report-request.d.ts +61 -0
  76. package/dist/diagnostics.d.ts +5 -0
  77. package/dist/diagnostics.js +209 -0
  78. package/dist/disclosure-CbLtajUQ.js +1 -0
  79. package/dist/dropdown-BwhViJFd.js +1 -0
  80. package/dist/elements/agent-card.js +1 -1
  81. package/dist/elements/artifact.js +1 -1
  82. package/dist/elements/attachments.js +1 -1
  83. package/dist/elements/audio-visualizer.js +1 -1
  84. package/dist/elements/autoloader.js +1 -1
  85. package/dist/elements/avatar.js +1 -1
  86. package/dist/elements/badge.js +1 -1
  87. package/dist/elements/button.js +1 -1
  88. package/dist/elements/card.js +1 -1
  89. package/dist/elements/cards.js +1 -1
  90. package/dist/elements/chain-of-thought.js +1 -1
  91. package/dist/elements/chat-scope-picker.js +1 -1
  92. package/dist/elements/chat-workspace.js +1 -1
  93. package/dist/elements/chat.js +1 -1
  94. package/dist/elements/checkbox-group.d.ts +1 -0
  95. package/dist/elements/checkbox-group.js +1 -0
  96. package/dist/elements/checkbox.d.ts +1 -0
  97. package/dist/elements/checkbox.js +1 -0
  98. package/dist/elements/checkpoint.js +1 -1
  99. package/dist/elements/choice.js +1 -1
  100. package/dist/elements/coachmark.js +1 -1
  101. package/dist/elements/code-block.js +1 -1
  102. package/dist/elements/command.js +1 -1
  103. package/dist/elements/compare.js +1 -1
  104. package/dist/elements/composer.js +1 -1
  105. package/dist/elements/confirm-card.js +1 -1
  106. package/dist/elements/context-meter.js +1 -1
  107. package/dist/elements/conversation-item.d.ts +1 -0
  108. package/dist/elements/conversation-item.js +1 -0
  109. package/dist/elements/conversation-list.js +1 -1
  110. package/dist/elements/default-input.d.ts +3 -3
  111. package/dist/elements/define-entry.d.ts +12 -0
  112. package/dist/elements/define.d.ts +27 -0
  113. package/dist/elements/diagnostic-events.d.ts +74 -0
  114. package/dist/elements/dialog.js +1 -1
  115. package/dist/elements/dock.d.ts +1 -0
  116. package/dist/elements/dock.js +243 -0
  117. package/dist/elements/dropdown.d.ts +1 -0
  118. package/dist/elements/dropdown.js +1 -0
  119. package/dist/elements/editable-label.js +1 -1
  120. package/dist/elements/element-data-types.d.ts +37 -0
  121. package/dist/elements/element-diagnostics.d.ts +81 -0
  122. package/dist/elements/embed.js +1 -1
  123. package/dist/elements/empty.js +1 -1
  124. package/dist/elements/feedback-bar.js +1 -1
  125. package/dist/elements/file-tree.js +1 -1
  126. package/dist/elements/file-upload.js +1 -1
  127. package/dist/elements/form.js +1 -1
  128. package/dist/elements/hover-card.js +1 -1
  129. package/dist/elements/icon.js +1 -1
  130. package/dist/elements/image.js +1 -1
  131. package/dist/elements/input.js +1 -1
  132. package/dist/elements/kbd.js +1 -1
  133. package/dist/elements/link-preview.js +1 -1
  134. package/dist/elements/loader.js +1 -1
  135. package/dist/elements/markdown.js +1 -1
  136. package/dist/elements/menu.js +1 -1
  137. package/dist/elements/message-skills.js +1 -1
  138. package/dist/elements/message.js +1 -1
  139. package/dist/elements/model-switcher.js +1 -1
  140. package/dist/elements/nav.js +1 -1
  141. package/dist/elements/notice.js +1 -1
  142. package/dist/elements/pane-grid.d.ts +1 -0
  143. package/dist/elements/pane-grid.js +1 -0
  144. package/dist/elements/pane-group.js +1 -1
  145. package/dist/elements/pane.js +1 -1
  146. package/dist/elements/popover.js +1 -1
  147. package/dist/elements/progress-bar.js +1 -1
  148. package/dist/elements/prompt-dock.js +1 -1
  149. package/dist/elements/prompt-input.js +1 -1
  150. package/dist/elements/prompt-suggestions.js +1 -1
  151. package/dist/elements/radio-group.d.ts +1 -0
  152. package/dist/elements/radio-group.js +1 -0
  153. package/dist/elements/reasoning.js +1 -1
  154. package/dist/elements/register.d.ts +2 -0
  155. package/dist/elements/remote.js +1 -1
  156. package/dist/elements/resizable.js +1 -1
  157. package/dist/elements/response-stream.js +3 -3
  158. package/dist/elements/screen.js +1 -1
  159. package/dist/elements/scroll-area.js +1 -1
  160. package/dist/elements/scroll-button.js +1 -1
  161. package/dist/elements/search.js +1 -1
  162. package/dist/elements/segmented.js +1 -1
  163. package/dist/elements/select.d.ts +1 -0
  164. package/dist/elements/select.js +1 -0
  165. package/dist/elements/separator.js +1 -1
  166. package/dist/elements/setting-item.js +1 -1
  167. package/dist/elements/settings-group.js +1 -1
  168. package/dist/elements/skeleton.js +1 -1
  169. package/dist/elements/slider.d.ts +1 -0
  170. package/dist/elements/slider.js +1 -0
  171. package/dist/elements/slots.d.ts +36 -4
  172. package/dist/elements/source.js +1 -1
  173. package/dist/elements/status.js +1 -1
  174. package/dist/elements/switch.js +1 -1
  175. package/dist/elements/tabs.js +1 -1
  176. package/dist/elements/tasks.js +1 -1
  177. package/dist/elements/text-shimmer.js +1 -1
  178. package/dist/elements/thinking-bar.js +1 -1
  179. package/dist/elements/thread.js +1 -1
  180. package/dist/elements/toast.js +1 -1
  181. package/dist/elements/tool.js +1 -1
  182. package/dist/elements/tooltip.js +1 -1
  183. package/dist/elements/voice-input.js +1 -1
  184. package/dist/elements/voice-output.js +1 -1
  185. package/dist/elements.d.ts +589 -167
  186. package/dist/{elements/chunks/ellipsis-CVxqfsDZ.js → ellipsis-DFr4Vqr3.js} +1 -1
  187. package/dist/embed-5s_vU4J0.js +1 -0
  188. package/dist/engine-javascript-vq0WuIJl.js +14 -2516
  189. package/dist/{elements/chunks/external-link-DG2sRdQL.js → external-link-u9d85ORQ.js} +1 -1
  190. package/dist/file-text-CX7_x42o.js +1 -0
  191. package/dist/{elements/chunks/file-tree-yGWNK0Js.js → file-tree-D3kBjXI5.js} +1 -1
  192. package/dist/folder-V-YdIL8f.js +1 -0
  193. package/dist/form-BRNUMCN2.js +1 -0
  194. package/dist/github-dark-dimmed-DUshB20C.js +1 -4
  195. package/dist/github-light-JYsPkUQd.js +1 -4
  196. package/dist/hover-card-DaeiYrTA.js +1 -0
  197. package/dist/html-CPZ3oZQ7.js +1 -10
  198. package/dist/icon-BpixdZNq.js +1 -0
  199. package/dist/{elements/chunks/index-BCRhi84a.js → index-xu_pdcPi.js} +1 -1
  200. package/dist/index.d.ts +3 -1
  201. package/dist/index.js +8473 -6470
  202. package/dist/index.server.js +6495 -4958
  203. package/dist/info-8mFsIjS3.js +1 -0
  204. package/dist/input-d1Yuu-hz.js +1 -0
  205. package/dist/javascript-C25yR2R2.js +1 -6
  206. package/dist/json-DxJze_jm.js +1 -6
  207. package/dist/kai-provider.es.js +40 -40
  208. package/dist/kai.es.js +1 -1
  209. package/dist/kbd-961zMPFB.js +1 -0
  210. package/dist/link-DlZZBGaR.js +1 -0
  211. package/dist/{elements/chunks/link-preview-Cf5KOP-i.js → link-preview-DIIbV2Sd.js} +1 -1
  212. package/dist/loader-YQszHFaW.js +1 -0
  213. package/dist/{elements/chunks/markdown-DbozyYqa.js → markdown-CVk1MPsj.js} +1 -1
  214. package/dist/mcp.es.js +3873 -544
  215. package/dist/message-CwKVEdZg.js +1 -0
  216. package/dist/message-DS8lzHc1.js +1 -0
  217. package/dist/message-circle-Xf8Q-vZp.js +1 -0
  218. package/dist/message-square-Cxnwgkns.js +1 -0
  219. package/dist/{elements/chunks/minimize-2-SegJ_oku.js → minimize-2-UEZmP2QT.js} +1 -1
  220. package/dist/{elements/chunks/model-switcher-D7JrFFHp.js → model-switcher-Kk1jEQ5t.js} +1 -1
  221. package/dist/{elements/chunks/overlay-CV7z2YuX.js → overlay-C1od6LOz.js} +1 -1
  222. package/dist/panel-right-ryET0yyn.js +1 -0
  223. package/dist/paperclip-BDNoZFJP.js +1 -0
  224. package/dist/play-OFIvYXUQ.js +1 -0
  225. package/dist/primitives/card-data-types.d.ts +49 -0
  226. package/dist/primitives/card-routing.d.ts +1 -33
  227. package/dist/primitives/card-validate.d.ts +2 -2
  228. package/dist/primitives/chat-config.d.ts +29 -2
  229. package/dist/primitives/field-mask.d.ts +96 -0
  230. package/dist/primitives/field-semantics.d.ts +36 -0
  231. package/dist/primitives/input-mask.d.ts +46 -0
  232. package/dist/primitives/url-scheme-policy.d.ts +34 -0
  233. package/dist/primitives/use-resize-observer.d.ts +23 -0
  234. package/dist/primitives/use-speech-recognition.d.ts +8 -0
  235. package/dist/primitives/use-text-stream.d.ts +5 -0
  236. package/dist/progress-bar-BvYX0aoy.js +1 -0
  237. package/dist/prompt-suggestion-BRFu2lcu.js +1 -0
  238. package/dist/radio-DcL23cNJ.js +1 -0
  239. package/dist/react/index.d.ts +306 -283
  240. package/dist/react.js +309 -247
  241. package/dist/reasoning-Cackq4Rh.js +1 -0
  242. package/dist/register-impl-C7rENvPK.js +424 -0
  243. package/dist/{elements/chunks/resizable-Dpzjlvp4.js → resizable-Cp9HUYih.js} +1 -1
  244. package/dist/rotate-ccw-0DLRDHH5.js +1 -0
  245. package/dist/rotate-cw-DOB9IGcU.js +1 -0
  246. package/dist/schemas/form.schema.json +21 -1
  247. package/dist/schemas/index.d.ts +1 -1
  248. package/dist/schemas/tool-defs.d.ts +45 -0
  249. package/dist/schemas.js +398 -305
  250. package/dist/scroll-area-emVmWP4K.js +1 -0
  251. package/dist/scroll-button-CeP_gv1x.js +1 -0
  252. package/dist/select-CWmu00tS.js +1 -0
  253. package/dist/{elements/chunks/separator-DH2r_ZSZ.js → separator-CE6vly6z.js} +1 -1
  254. package/dist/{elements/chunks/settings-BFMOd6yB.js → settings-CE-78SvZ.js} +1 -1
  255. package/dist/{elements/chunks/settings-group-B3VZKIcz.js → settings-group-ZFWNxFQR.js} +1 -1
  256. package/dist/{elements/chunks/skeleton-N8BuWYmf.js → skeleton-BebdP4mf.js} +1 -1
  257. package/dist/slider-BAKRYUlz.js +1 -0
  258. package/dist/slots-DaNjX0rc.js +1 -0
  259. package/dist/{solid-BMuDmFo_.js → solid-BE5ui6sy.js} +10672 -8116
  260. package/dist/{solid-CGYNdLRR.js → solid-DFhsce3O.js} +8137 -6056
  261. package/dist/solid.d.ts +15 -0
  262. package/dist/solid.js +248 -235
  263. package/dist/solid.server.js +248 -235
  264. package/dist/source-B0FlguSx.js +1 -0
  265. package/dist/star-CBMZvLuN.js +1 -0
  266. package/dist/state/index.d.ts +5 -1
  267. package/dist/state/mock.d.ts +32 -2
  268. package/dist/state/persistence.d.ts +51 -0
  269. package/dist/state/stream.d.ts +50 -0
  270. package/dist/state/threads.d.ts +71 -0
  271. package/dist/state.js +297 -172
  272. package/dist/store-7eoadydQ.js +1 -0
  273. package/dist/svelte--5p79yCD.js +1 -15
  274. package/dist/switch-CViARZCy.js +1 -0
  275. package/dist/tasks-card-MjCcOhR_.js +1 -0
  276. package/dist/text-shimmer-DKlwRF2G.js +1 -0
  277. package/dist/textarea-3ay2Me2-.js +1 -0
  278. package/dist/theme.tokens.css +82 -13
  279. package/dist/{elements/chunks/thumbs-up-DQe0hvkZ.js → thumbs-up-DQcu2HMO.js} +1 -1
  280. package/dist/toast-store-C6yKOhbk.js +1 -0
  281. package/dist/{elements/chunks/tool-C1YtxwPu.js → tool-BCYNlfKy.js} +1 -1
  282. package/dist/{elements/chunks/tooltip-BqwnFWhn.js → tooltip-05zI4hjs.js} +1 -1
  283. package/dist/trash-2-BR1RxGky.js +1 -0
  284. package/dist/{elements/chunks/triangle-alert-B6or7F5u.js → triangle-alert-DHohDOCy.js} +1 -1
  285. package/dist/tsx-B8rCNbgL.js +1 -6
  286. package/dist/types.d.ts +4 -2
  287. package/dist/typescript-RycA9KXf.js +1 -6
  288. package/dist/ui/checkbox-group.d.ts +83 -0
  289. package/dist/ui/checkbox.d.ts +40 -0
  290. package/dist/ui/dock.d.ts +131 -0
  291. package/dist/ui/hover-card.d.ts +44 -0
  292. package/dist/ui/icon.d.ts +3 -0
  293. package/dist/ui/input.d.ts +48 -2
  294. package/dist/ui/radio.d.ts +85 -0
  295. package/dist/ui/select.d.ts +71 -0
  296. package/dist/ui/slider.d.ts +65 -0
  297. package/dist/ui/switch.d.ts +9 -2
  298. package/dist/upload-BbGW6A_u.js +1 -0
  299. package/dist/url-scheme-policy-DHpoTJwB.js +1 -0
  300. package/dist/use-card-resolution-CJW4grFa.js +1 -0
  301. package/dist/{variant-aurora-DwSOfraQ.js → variant-aurora-BUOVgPOB.js} +27 -27
  302. package/dist/{variant-aurora-wKvAQ5wp.js → variant-aurora-CUsUJvFI.js} +28 -28
  303. package/dist/{variant-aurora-XEkPT0_z.js → variant-aurora-CW2i4bfr.js} +2 -2
  304. package/dist/{elements/chunks/variant-aurora-QXTZPyST.js → variant-aurora-xiMPty8f.js} +2 -2
  305. package/dist/variant-custom-BQtOnmeO.js +1 -0
  306. package/dist/{variant-custom-BhS9wIpU.js → variant-custom-CAm9L-E5.js} +65 -65
  307. package/dist/{variant-custom-eFIg2XWQ.js → variant-custom-CAnzzppW.js} +40 -40
  308. package/dist/variant-custom-D91HjAKz.js +1 -0
  309. package/dist/{variant-wave-CUWGx9Bn.js → variant-wave-Ca1Ls4_y.js} +21 -21
  310. package/dist/{variant-wave-CbVsmgwT.js → variant-wave-CxX39DKd.js} +25 -25
  311. package/dist/{variant-wave-BwzrHD1s.js → variant-wave-DYyzIIZv.js} +2 -2
  312. package/dist/{elements/chunks/variant-wave-DDCwhLas.js → variant-wave-uY5crU_K.js} +2 -2
  313. package/dist/vue-BmIZj4XD.js +1 -33
  314. package/dist/wire/chunk.d.ts +47 -0
  315. package/dist/wire/diagnostics.d.ts +575 -0
  316. package/dist/wire/encode-probe.d.ts +70 -0
  317. package/dist/wire/encode.d.ts +24 -0
  318. package/dist/wire/index.d.ts +2 -0
  319. package/dist/wire/sse.d.ts +10 -2
  320. package/dist/wire.js +917 -480
  321. package/dist/x-C5m1JFgi.js +1 -0
  322. package/frameworks/react/index.tsx +325 -108
  323. package/llms-full.txt +1354 -82
  324. package/llms.txt +6 -3
  325. package/package.json +39 -6
  326. package/src/agent-tooling/archetypes.ts +41 -9
  327. package/src/agent-tooling/catalog/README.md +676 -0
  328. package/src/agent-tooling/catalog/catalog-types.ts +231 -0
  329. package/src/agent-tooling/catalog/fabrications.ts +96 -0
  330. package/src/agent-tooling/catalog/invariants.ts +284 -0
  331. package/src/agent-tooling/catalog/labs-titles.ts +114 -0
  332. package/src/agent-tooling/catalog/scenarios.ts +87 -0
  333. package/src/agent-tooling/catalog/surfaces.ts +347 -0
  334. package/src/agent-tooling/construct/cli-entry.ts +8 -0
  335. package/src/agent-tooling/construct/cli.ts +131 -0
  336. package/src/agent-tooling/construct/codegen.ts +1353 -0
  337. package/src/agent-tooling/construct/construct.v1.schema.json +250 -0
  338. package/src/agent-tooling/construct/dev.ts +148 -0
  339. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +7 -0
  340. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +44 -0
  341. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +23 -0
  342. package/src/agent-tooling/construct/schema.ts +371 -0
  343. package/src/agent-tooling/integrations/anthropic.ts +7 -1
  344. package/src/agent-tooling/integrations/cloudflare.ts +43 -2
  345. package/src/agent-tooling/integrations/langgraph.ts +7 -1
  346. package/src/agent-tooling/integrations/mastra.ts +7 -1
  347. package/src/agent-tooling/integrations/mock.ts +92 -17
  348. package/src/agent-tooling/integrations/ollama.ts +7 -1
  349. package/src/agent-tooling/integrations/openai.ts +7 -1
  350. package/src/agent-tooling/integrations/openrouter.ts +7 -1
  351. package/src/agent-tooling/integrations/pi.ts +56 -1
  352. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +7 -1
  353. package/src/agent-tooling/mcp/css-raw.d.ts +12 -0
  354. package/src/agent-tooling/mcp/manifest.ts +100 -1
  355. package/src/agent-tooling/mcp/server.ts +63 -6
  356. package/src/agent-tooling/mcp/tools/construct.ts +130 -0
  357. package/src/agent-tooling/mcp/tools/debug.ts +126 -4
  358. package/src/agent-tooling/mcp/tools/reference.ts +542 -5
  359. package/src/agent-tooling/mcp/tools/scaffold.ts +1834 -307
  360. package/src/agent-tooling/mcp/tools/theme.ts +146 -30
  361. package/src/agent-tooling/mcp/validate-args.ts +141 -0
  362. package/src/agent-tooling/recipes/composed-thread.ts +714 -0
  363. package/src/agent-tooling/recipes/index.ts +22 -0
  364. package/src/agent-tooling/recipes/types.ts +32 -0
  365. package/src/agent-tooling/registry.ts +24 -7
  366. package/src/agent-tooling/route-emit.ts +26 -2
  367. package/src/components/attachment-types.ts +54 -1
  368. package/src/components/attachments.tsx +169 -22
  369. package/src/components/audio-visualizer/fit-scale.ts +112 -0
  370. package/src/components/audio-visualizer/index.tsx +80 -3
  371. package/src/components/audio-visualizer/variant-aurora.tsx +10 -4
  372. package/src/components/audio-visualizer/variant-bar.tsx +38 -6
  373. package/src/components/audio-visualizer/variant-custom.tsx +8 -2
  374. package/src/components/audio-visualizer/variant-grid.tsx +16 -11
  375. package/src/components/audio-visualizer/variant-radial.tsx +15 -10
  376. package/src/components/audio-visualizer/variant-wave.tsx +7 -2
  377. package/src/components/card-renderer.tsx +39 -8
  378. package/src/components/card.tsx +10 -2
  379. package/src/components/chat-container.tsx +4 -1
  380. package/src/components/chat-scope-picker.tsx +2 -2
  381. package/src/components/chat-thread.tsx +105 -13
  382. package/src/components/choice-card.tsx +102 -37
  383. package/src/components/coachmark.tsx +1 -1
  384. package/src/components/code-block.tsx +81 -5
  385. package/src/components/composer.tsx +89 -8
  386. package/src/components/confirm-card.tsx +20 -4
  387. package/src/components/conversation-item.tsx +138 -4
  388. package/src/components/conversation-list.tsx +230 -15
  389. package/src/components/embed.tsx +4 -0
  390. package/src/components/empty.tsx +14 -3
  391. package/src/components/file-tree.tsx +5 -1
  392. package/src/components/form-widgets.tsx +257 -195
  393. package/src/components/form.tsx +336 -21
  394. package/src/components/loader.tsx +12 -5
  395. package/src/components/message-skills.tsx +1 -1
  396. package/src/components/message.tsx +142 -12
  397. package/src/components/prompt-input.tsx +7 -1
  398. package/src/components/prompt-suggestion.tsx +4 -1
  399. package/src/components/reasoning.tsx +30 -3
  400. package/src/components/response-compare.tsx +2 -2
  401. package/src/components/response-stream.tsx +13 -7
  402. package/src/components/screen.tsx +5 -0
  403. package/src/components/scroll-button.tsx +63 -4
  404. package/src/components/source.tsx +6 -1
  405. package/src/components/tasks-card.tsx +58 -16
  406. package/src/components/thread.tsx +10 -1
  407. package/src/components/toast.tsx +11 -5
  408. package/src/components/tool-types.ts +9 -0
  409. package/src/components/voice-input.tsx +35 -3
  410. package/src/components/voice-output.tsx +46 -6
  411. package/src/components/workspace-shell.tsx +285 -0
  412. package/src/diagnostics/hook.ts +352 -0
  413. package/src/diagnostics/index.ts +82 -0
  414. package/src/diagnostics/report-request.ts +296 -0
  415. package/src/elements/attachments.tsx +9 -8
  416. package/src/elements/audio-visualizer.tsx +48 -4
  417. package/src/elements/chat-workspace.tsx +159 -287
  418. package/src/elements/chat.tsx +31 -10
  419. package/src/elements/checkbox-group.tsx +164 -0
  420. package/src/elements/checkbox.tsx +134 -0
  421. package/src/elements/code-block.tsx +19 -1
  422. package/src/elements/command.tsx +4 -1
  423. package/src/elements/compiled.css +1 -1
  424. package/src/elements/composer.tsx +12 -1
  425. package/src/elements/conversation-item.tsx +120 -0
  426. package/src/elements/conversation-list.tsx +60 -11
  427. package/src/elements/default-input.tsx +5 -5
  428. package/src/elements/define-entry.ts +12 -0
  429. package/src/elements/define.tsx +168 -8
  430. package/src/elements/diagnostic-events.ts +114 -0
  431. package/src/elements/dialog.tsx +47 -0
  432. package/src/elements/disclosure.ts +34 -12
  433. package/src/elements/dock.tsx +215 -0
  434. package/src/elements/dropdown.tsx +123 -0
  435. package/src/elements/element-data-types.ts +40 -0
  436. package/src/elements/element-diagnostics.ts +392 -0
  437. package/src/elements/element-manifest.json +36 -0
  438. package/src/elements/element-meta.json +1483 -560
  439. package/src/elements/element-nonscalar.json +185 -0
  440. package/src/elements/element-types.d.ts +589 -167
  441. package/src/elements/feedback-bar.tsx +5 -0
  442. package/src/elements/icon-names.json +29 -0
  443. package/src/elements/input.tsx +312 -23
  444. package/src/elements/menu.tsx +13 -0
  445. package/src/elements/message.tsx +2 -0
  446. package/src/elements/pane-grid.tsx +111 -0
  447. package/src/elements/prompt-dock.tsx +2 -1
  448. package/src/elements/prompt-input.tsx +16 -10
  449. package/src/elements/radio-group.tsx +129 -0
  450. package/src/elements/register-impl.ts +52 -0
  451. package/src/elements/register.ts +28 -0
  452. package/src/elements/resizable.tsx +52 -25
  453. package/src/elements/scroll-button.tsx +59 -6
  454. package/src/elements/select.tsx +165 -0
  455. package/src/elements/slider.tsx +171 -0
  456. package/src/elements/slots.ts +108 -13
  457. package/src/elements/styles.css +119 -9
  458. package/src/elements/thinking-bar.tsx +16 -7
  459. package/src/elements/thread.tsx +2 -0
  460. package/src/elements/toast.tsx +17 -1
  461. package/src/elements/tool.tsx +26 -5
  462. package/src/elements/voice-input.tsx +11 -2
  463. package/src/elements/voice-output.tsx +16 -3
  464. package/src/index.ts +4 -1
  465. package/src/primitives/card-data-types.ts +49 -0
  466. package/src/primitives/card-host.tsx +4 -2
  467. package/src/primitives/card-routing.ts +7 -56
  468. package/src/primitives/card-schemas/form.schema.json +21 -1
  469. package/src/primitives/card-validate.ts +10 -2
  470. package/src/primitives/chat-config.tsx +33 -6
  471. package/src/primitives/field-mask.ts +256 -0
  472. package/src/primitives/field-semantics.ts +115 -0
  473. package/src/primitives/input-mask.ts +853 -0
  474. package/src/primitives/toast-store.ts +66 -4
  475. package/src/primitives/url-scheme-policy.ts +70 -0
  476. package/src/primitives/use-resize-observer.ts +33 -0
  477. package/src/primitives/use-speech-recognition.ts +12 -1
  478. package/src/primitives/use-stick-to-bottom.ts +34 -2
  479. package/src/primitives/use-text-stream.ts +33 -2
  480. package/src/remote/provider-runtime.ts +6 -3
  481. package/src/schemas/index.ts +1 -0
  482. package/src/schemas/tool-defs.ts +307 -6
  483. package/src/solid.ts +15 -0
  484. package/src/state/index.ts +13 -1
  485. package/src/state/mock.ts +92 -6
  486. package/src/state/persistence.ts +180 -0
  487. package/src/state/stream.ts +71 -4
  488. package/src/state/threads.ts +142 -0
  489. package/src/types.ts +4 -2
  490. package/src/ui/agent-card.tsx +2 -2
  491. package/src/ui/avatar.tsx +1 -1
  492. package/src/ui/checkbox-group.tsx +153 -0
  493. package/src/ui/checkbox.tsx +63 -0
  494. package/src/ui/dialog.tsx +6 -0
  495. package/src/ui/dock.tsx +584 -0
  496. package/src/ui/dropdown.tsx +67 -23
  497. package/src/ui/hover-card.tsx +156 -6
  498. package/src/ui/icon.tsx +53 -0
  499. package/src/ui/input.tsx +275 -16
  500. package/src/ui/kbd.tsx +1 -1
  501. package/src/ui/nav.tsx +1 -1
  502. package/src/ui/pane-group.tsx +2 -2
  503. package/src/ui/radio.tsx +150 -0
  504. package/src/ui/resizable.tsx +11 -0
  505. package/src/ui/select.tsx +168 -0
  506. package/src/ui/slider.tsx +178 -0
  507. package/src/ui/switch.tsx +49 -18
  508. package/src/utils/cn.ts +11 -5
  509. package/src/wire/chunk.ts +47 -0
  510. package/src/wire/consume.ts +185 -26
  511. package/src/wire/diagnostics.ts +727 -0
  512. package/src/wire/encode-probe.ts +214 -0
  513. package/src/wire/encode.ts +267 -14
  514. package/src/wire/formats/anthropic.ts +8 -1
  515. package/src/wire/formats/openai.ts +5 -0
  516. package/src/wire/index.ts +22 -0
  517. package/src/wire/read.ts +250 -6
  518. package/src/wire/sse.ts +16 -3
  519. package/theme.css +84 -13
  520. package/dist/elements/chunks/action-icons-DW9muWrY.js +0 -1
  521. package/dist/elements/chunks/arrow-left-iJVnQmxA.js +0 -1
  522. package/dist/elements/chunks/artifact-BSuPYFHY.js +0 -1
  523. package/dist/elements/chunks/attachments-CL6TaqIb.js +0 -1
  524. package/dist/elements/chunks/audio-visualizer-BuUqQmaO.js +0 -1
  525. package/dist/elements/chunks/badge-TIMiJFKc.js +0 -1
  526. package/dist/elements/chunks/bash-InADTalH.js +0 -1
  527. package/dist/elements/chunks/card-renderer-CSoTL_e1.js +0 -1
  528. package/dist/elements/chunks/card-routing-BK09BdmL.js +0 -1
  529. package/dist/elements/chunks/chat-thread-DxoKaStk.js +0 -1
  530. package/dist/elements/chunks/check-MdLzbxrm.js +0 -1
  531. package/dist/elements/chunks/chevron-down-MK7IzDqe.js +0 -1
  532. package/dist/elements/chunks/chevron-right-C5jXhmtV.js +0 -1
  533. package/dist/elements/chunks/choice-card-CGMc3kek.js +0 -1
  534. package/dist/elements/chunks/circle-BG7VkPep.js +0 -1
  535. package/dist/elements/chunks/circle-check-GqvO2UBs.js +0 -1
  536. package/dist/elements/chunks/circle-x-mhH7pOK2.js +0 -1
  537. package/dist/elements/chunks/code-block-ClhQO9RW.js +0 -1
  538. package/dist/elements/chunks/collapsible-DBcBkFPh.js +0 -1
  539. package/dist/elements/chunks/composer-CZZmtYOT.js +0 -69
  540. package/dist/elements/chunks/confirm-card-BWjf2-xo.js +0 -1
  541. package/dist/elements/chunks/context-hKjNqiyQ.js +0 -1
  542. package/dist/elements/chunks/conversation-list-CsGJjSKG.js +0 -1
  543. package/dist/elements/chunks/core-AYMC6_lb.js +0 -12
  544. package/dist/elements/chunks/css-M7EaDHN_.js +0 -1
  545. package/dist/elements/chunks/default-input-B1Mem5wu.js +0 -1
  546. package/dist/elements/chunks/define-B_tXMYRm.js +0 -1
  547. package/dist/elements/chunks/disclosure-DAoYOKew.js +0 -1
  548. package/dist/elements/chunks/download-DnCyWFJE.js +0 -1
  549. package/dist/elements/chunks/dropdown-CmNna5lT.js +0 -1
  550. package/dist/elements/chunks/embed-CjAD2jSi.js +0 -1
  551. package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +0 -141
  552. package/dist/elements/chunks/file-text-D0J9F6M7.js +0 -1
  553. package/dist/elements/chunks/folder-NV1pi_ud.js +0 -1
  554. package/dist/elements/chunks/form-Cp8Y00Wn.js +0 -1
  555. package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +0 -1
  556. package/dist/elements/chunks/github-light-JYsPkUQd.js +0 -1
  557. package/dist/elements/chunks/hover-card-6KtXpLwT.js +0 -1
  558. package/dist/elements/chunks/html-CPZ3oZQ7.js +0 -1
  559. package/dist/elements/chunks/icon-97R8SR2p.js +0 -1
  560. package/dist/elements/chunks/info-C8r5Q6cc.js +0 -1
  561. package/dist/elements/chunks/input-DrseEjhp.js +0 -1
  562. package/dist/elements/chunks/javascript-C25yR2R2.js +0 -1
  563. package/dist/elements/chunks/json-DxJze_jm.js +0 -1
  564. package/dist/elements/chunks/kbd-OGJDUT-O.js +0 -1
  565. package/dist/elements/chunks/link-BdsfLB7b.js +0 -1
  566. package/dist/elements/chunks/loader-B5QzK_8_.js +0 -1
  567. package/dist/elements/chunks/message-CE4k-qaj.js +0 -1
  568. package/dist/elements/chunks/message-DtXKPqiR.js +0 -1
  569. package/dist/elements/chunks/message-square-C9ovmtOo.js +0 -1
  570. package/dist/elements/chunks/paperclip-Bg0ITU3b.js +0 -1
  571. package/dist/elements/chunks/progress-bar-D1_rzt6N.js +0 -1
  572. package/dist/elements/chunks/prompt-suggestion-D5Sm8xF1.js +0 -1
  573. package/dist/elements/chunks/reasoning-BrxQfpfI.js +0 -1
  574. package/dist/elements/chunks/rotate-cw-DzVDJOA1.js +0 -1
  575. package/dist/elements/chunks/scroll-area-93A1bbeG.js +0 -1
  576. package/dist/elements/chunks/scroll-button-CrTo7wm4.js +0 -1
  577. package/dist/elements/chunks/share-DgNbkJKY.js +0 -1
  578. package/dist/elements/chunks/slots-CIw9RlAe.js +0 -1
  579. package/dist/elements/chunks/source-w9V0NnBn.js +0 -1
  580. package/dist/elements/chunks/star-DHvACxtm.js +0 -1
  581. package/dist/elements/chunks/store-HIPGhNz9.js +0 -1
  582. package/dist/elements/chunks/svelte--5p79yCD.js +0 -1
  583. package/dist/elements/chunks/tasks-card-lPxoodlA.js +0 -1
  584. package/dist/elements/chunks/text-shimmer-BY_rI3s5.js +0 -1
  585. package/dist/elements/chunks/textarea-DPfuhswM.js +0 -1
  586. package/dist/elements/chunks/toast-store-VUZZBhzH.js +0 -1
  587. package/dist/elements/chunks/tsx-B8rCNbgL.js +0 -1
  588. package/dist/elements/chunks/typescript-RycA9KXf.js +0 -1
  589. package/dist/elements/chunks/use-card-resolution-DJg32jGH.js +0 -1
  590. package/dist/elements/chunks/variant-custom-D5ZlmziF.js +0 -1
  591. package/dist/elements/chunks/video-Bb86fVYI.js +0 -1
  592. package/dist/elements/chunks/vue-BmIZj4XD.js +0 -1
  593. package/dist/elements/chunks/x-BOhjBeOd.js +0 -1
  594. package/dist/llms/llms-full.txt +0 -2834
  595. package/dist/llms/llms.txt +0 -156
  596. package/dist/primitives/card-validate-generator.testlib.d.ts +0 -20
  597. package/dist/register-impl-DGmGzrEM.js +0 -145
  598. package/dist/ui/stat.d.ts +0 -16
  599. package/dist/variant-custom-MkTNTycd.js +0 -1
  600. package/src/primitives/card-validate-generator.testlib.ts +0 -38
  601. package/src/ui/stat.tsx +0 -41
  602. /package/dist/{elements/chunks/card-tags-D8lZ-C_U.js → card-tags-D8lZ-C_U.js} +0 -0
  603. /package/dist/{elements/chunks/link-preview-DNILK391.js → link-preview-DNILK391.js} +0 -0
@@ -378,7 +378,7 @@
378
378
  "type": "undefined | { id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[]",
379
379
  "optional": true,
380
380
  "scalar": false,
381
- "description": "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).",
381
+ "description": "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.",
382
382
  "typeName": "AttachmentData[]",
383
383
  "typeShape": "{ id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[]",
384
384
  "default": "[]",
@@ -492,6 +492,16 @@
492
492
  "name": "preview",
493
493
  "doc": "The image shown in an attachment’s hover-card preview. Bounded by default (max ~320×256, aspect preserved) so a large image never blows up the card. Raise or lower the cap from outside.",
494
494
  "recipe": "kai-attachments::part(preview) { max-width: 32rem; max-height: 24rem }"
495
+ },
496
+ {
497
+ "name": "attachment",
498
+ "doc": "One attachment item: the chip, row or tile, whichever variant is rendering. Restyle its background, radius or border from outside without caring which layout it is.",
499
+ "recipe": "kai-chat::part(attachment) { border-radius: 0.25rem }"
500
+ },
501
+ {
502
+ "name": "attachment-name",
503
+ "doc": "The attachment’s filename label. Present in every variant that shows one (a grid tile omits it for an image, which is its own label). Retune its type or hide it entirely.",
504
+ "recipe": "kai-chat::part(attachment-name) { font-size: 0.75rem }"
495
505
  }
496
506
  ]
497
507
  },
@@ -606,7 +616,7 @@
606
616
  "type": "undefined | MediaStream",
607
617
  "optional": true,
608
618
  "scalar": false,
609
- "description": "Live microphone or WebRTC audio to analyze. JS property only.",
619
+ "description": "Live microphone or WebRTC audio to analyze. JS property only. NOTE: amplitude renders only while state is \"speaking\" unless listening-amplitude is set; every other state plays its scripted animation and ignores the audio.",
610
620
  "displayType": "undefined | MediaStream"
611
621
  },
612
622
  {
@@ -614,7 +624,7 @@
614
624
  "type": "undefined | HTMLMediaElement",
615
625
  "optional": true,
616
626
  "scalar": false,
617
- "description": "An `<audio>` or `<video>` element to tap for its audio. JS property only.",
627
+ "description": "An `<audio>` or `<video>` element to tap for its audio. JS property only. NOTE: amplitude renders only while state is \"speaking\" unless listening-amplitude is set; every other state plays its scripted animation and ignores the audio.",
618
628
  "displayType": "undefined | HTMLMediaElement"
619
629
  },
620
630
  {
@@ -622,9 +632,17 @@
622
632
  "type": "undefined | number[]",
623
633
  "optional": true,
624
634
  "scalar": false,
625
- "description": "Pre-computed levels, 0..1. Set this and no AudioContext is ever built, which is what keeps headless/SSR rendering and browser-speech-synthesis playback (which exposes no audio node) free of Web Audio entirely. JS property only. A new array reference is required for each update; mutating the existing array in place will not re-render.",
635
+ "description": "Pre-computed levels, 0..1. Set this and no AudioContext is ever built, which is what keeps headless/SSR rendering and browser-speech-synthesis playback (which exposes no audio node) free of Web Audio entirely. JS property only. A new array reference is required for each update; mutating the existing array in place will not re-render. NOTE: amplitude renders only while state is \"speaking\" unless listening-amplitude is set; every other state plays its scripted animation and ignores the audio.",
626
636
  "displayType": "undefined | number[]"
627
637
  },
638
+ {
639
+ "name": "listeningAmplitude",
640
+ "type": "undefined | false | true",
641
+ "optional": true,
642
+ "scalar": true,
643
+ "description": "Render live amplitude during the listening state as well, using the same presentation as speaking. Off by default, which keeps LiveKit parity: amplitude from stream, audio-element or bands renders only while state is \"speaking\". Set it to show a real mic-level picture while the user is the one talking. Boolean. Attribute: `listening-amplitude` (a bare attribute means true; reflected, so the property reads back what the attribute set).",
644
+ "displayType": "undefined | false | true"
645
+ },
628
646
  {
629
647
  "name": "shader",
630
648
  "type": "undefined | { fragment: string; uniforms?: undefined | Record<string, { type: \"1f\" | \"1i\" | \"1fv\" | \"2f\" | \"3f\" | \"3fv\" | \"4f\" | \"4fv\" | \"Matrix2fv\" | \"Matrix3fv\" | \"Matrix4fv\"; value: number | number[] }> }",
@@ -1165,14 +1183,14 @@
1165
1183
  },
1166
1184
  {
1167
1185
  "name": "policy",
1168
- "type": "undefined | { onSubmit?: undefined | (cardId: string, data: unknown) => void; onAction?: undefined | (cardId: string, action: string, payload?: unknown) => void; onSendPrompt?: undefined | (text: string, opts: { mode: \"compose\" | \"send\"; context?: unknown; }) => void; onOpen?: undefined | (url: string, target: \"tab\" | \"artifact\") => void; onState?: undefined | (cardId: string, patch: unknown) => void; onDismiss?: undefined | (cardId: string) => void; onReopen?: undefined | (cardId: string) => void; onError?: undefined | (cardId: string, message: string) => void; maxSendPromptMode?: undefined | \"compose\" | \"send\" }",
1186
+ "type": "undefined | { onSubmit?: undefined | ((cardId: string, data: unknown) => void); onAction?: undefined | ((cardId: string, action: string, payload?: unknown) => void); onSendPrompt?: undefined | ((text: string, opts: { mode: \"compose\" | \"send\"; context?: unknown; }) => void); onOpen?: undefined | ((url: string, target: \"tab\" | \"artifact\") => void); onState?: undefined | ((cardId: string, patch: unknown) => void); onDismiss?: undefined | ((cardId: string) => void); onReopen?: undefined | ((cardId: string) => void); onError?: undefined | ((cardId: string, message: string) => void); maxSendPromptMode?: undefined | \"compose\" | \"send\" }",
1169
1187
  "optional": true,
1170
1188
  "scalar": false,
1171
1189
  "description": "Optional CardPolicy handling child events. Property: `el.policy`.",
1172
1190
  "typeName": "CardPolicy",
1173
- "typeShape": "{ onSubmit?: undefined | (cardId: string, data: unknown) => void; onAction?: undefined | (cardId: string, action: string, payload?: unknown) => void; onSendPrompt?: undefined | (text: string, opts: { mode: \"compose\" | \"send\"; context?: unknown; }) => void; onOpen?: undefined | (url: string, target: \"tab\" | \"artifact\") => void; onState?: undefined | (cardId: string, patch: unknown) => void; onDismiss?: undefined | (cardId: string) => void; onReopen?: undefined | (cardId: string) => void; onError?: undefined | (cardId: string, message: string) => void; maxSendPromptMode?: undefined | \"compose\" | \"send\" }",
1191
+ "typeShape": "{ onSubmit?: undefined | ((cardId: string, data: unknown) => void); onAction?: undefined | ((cardId: string, action: string, payload?: unknown) => void); onSendPrompt?: undefined | ((text: string, opts: { mode: \"compose\" | \"send\"; context?: unknown; }) => void); onOpen?: undefined | ((url: string, target: \"tab\" | \"artifact\") => void); onState?: undefined | ((cardId: string, patch: unknown) => void); onDismiss?: undefined | ((cardId: string) => void); onReopen?: undefined | ((cardId: string) => void); onError?: undefined | ((cardId: string, message: string) => void); maxSendPromptMode?: undefined | \"compose\" | \"send\" }",
1174
1192
  "typeImport": "CardPolicy",
1175
- "displayType": "undefined | { onSubmit?: undefined | (cardId: string, data: unknown) => void; onAction?: undefined | (cardId: string, action: string, payload?: unknown) => void; onSendPrompt?: undefined | (text: string, opts: { mode: \"compose\" | \"send\"; context?: unknown; }) => void; onOpen?: undefined | (url: string, target: \"tab\" | \"artifact\") => void; onState?: undefined | (cardId: string, patch: unknown) => void; onDismiss?: undefined | (cardId: string) => void; onReopen?: undefined | (cardId: string) => void; onError?: undefined | (cardId: string, message: string) => void; maxSendPromptMode?: undefined | \"compose\" | \"send\" }"
1193
+ "displayType": "undefined | { onSubmit?: undefined | ((cardId: string, data: unknown) => void); onAction?: undefined | ((cardId: string, action: string, payload?: unknown) => void); onSendPrompt?: undefined | ((text: string, opts: { mode: \"compose\" | \"send\"; context?: unknown; }) => void); onOpen?: undefined | ((url: string, target: \"tab\" | \"artifact\") => void); onState?: undefined | ((cardId: string, patch: unknown) => void); onDismiss?: undefined | ((cardId: string) => void); onReopen?: undefined | ((cardId: string) => void); onError?: undefined | ((cardId: string, message: string) => void); maxSendPromptMode?: undefined | \"compose\" | \"send\" }"
1176
1194
  },
1177
1195
  {
1178
1196
  "name": "validateCards",
@@ -1336,15 +1354,6 @@
1336
1354
  "universal": true,
1337
1355
  "displayType": "\"light\" | \"dark\" | \"auto\""
1338
1356
  },
1339
- {
1340
- "name": "search",
1341
- "type": "undefined | false | true",
1342
- "optional": true,
1343
- "scalar": true,
1344
- "description": "Show a Search (Globe) button in the input toolbar; fires a `search` event.",
1345
- "default": "false",
1346
- "displayType": "undefined | false | true"
1347
- },
1348
1357
  {
1349
1358
  "name": "value",
1350
1359
  "type": "undefined | string | ({ type: \"text\"; text: string } | { type: \"entity\"; entity: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown> } })[]",
@@ -1424,6 +1433,22 @@
1424
1433
  "default": "true",
1425
1434
  "displayType": "undefined | false | true"
1426
1435
  },
1436
+ {
1437
+ "name": "reasoning",
1438
+ "type": "undefined | \"full\" | \"compact\" | \"off\"",
1439
+ "optional": true,
1440
+ "scalar": true,
1441
+ "description": "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`.",
1442
+ "displayType": "undefined | \"full\" | \"compact\" | \"off\""
1443
+ },
1444
+ {
1445
+ "name": "reasoningOpen",
1446
+ "type": "undefined | false | true",
1447
+ "optional": true,
1448
+ "scalar": true,
1449
+ "description": "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`.",
1450
+ "displayType": "undefined | false | true"
1451
+ },
1427
1452
  {
1428
1453
  "name": "chatTitle",
1429
1454
  "type": "undefined | string",
@@ -1535,6 +1560,24 @@
1535
1560
  "description": "INJECT: footer row below the composer (disclaimers, token meter, …).",
1536
1561
  "displayType": "undefined | false | true"
1537
1562
  },
1563
+ {
1564
+ "name": "attach",
1565
+ "type": "undefined | false | true",
1566
+ "optional": true,
1567
+ "scalar": true,
1568
+ "description": "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.",
1569
+ "default": "true",
1570
+ "displayType": "undefined | false | true"
1571
+ },
1572
+ {
1573
+ "name": "webSearch",
1574
+ "type": "undefined | false | true",
1575
+ "optional": true,
1576
+ "scalar": true,
1577
+ "description": "Show a web-search (Globe) button in the input toolbar; calls `onWebSearch`.",
1578
+ "default": "false",
1579
+ "displayType": "undefined | false | true"
1580
+ },
1538
1581
  {
1539
1582
  "name": "voice",
1540
1583
  "type": "undefined | false | true",
@@ -1634,12 +1677,6 @@
1634
1677
  "description": "The header model switcher changed.",
1635
1678
  "displayDetail": "{ modelId: string }"
1636
1679
  },
1637
- {
1638
- "name": "kai-search",
1639
- "detail": "Record<string, never>",
1640
- "description": "The Search button was clicked.",
1641
- "displayDetail": "Record<string, never>"
1642
- },
1643
1680
  {
1644
1681
  "name": "kai-submit",
1645
1682
  "detail": "{ value: string; attachments: { id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[] }",
@@ -1663,6 +1700,12 @@
1663
1700
  "detail": "Record<string, never>",
1664
1701
  "description": "The Mic / voice button was clicked.",
1665
1702
  "displayDetail": "Record<string, never>"
1703
+ },
1704
+ {
1705
+ "name": "kai-web-search",
1706
+ "detail": "Record<string, never>",
1707
+ "description": "The web-search (Globe) toolbar button was clicked.",
1708
+ "displayDetail": "Record<string, never>"
1666
1709
  }
1667
1710
  ],
1668
1711
  "methods": [
@@ -1770,6 +1813,202 @@
1770
1813
  }
1771
1814
  ]
1772
1815
  },
1816
+ {
1817
+ "tag": "kai-checkbox",
1818
+ "className": "KaiCheckboxElement",
1819
+ "displayName": "Checkbox",
1820
+ "props": [
1821
+ {
1822
+ "name": "theme",
1823
+ "type": "\"light\" | \"dark\" | \"auto\"",
1824
+ "optional": true,
1825
+ "scalar": true,
1826
+ "description": "Color mode (`auto` follows prefers-color-scheme).",
1827
+ "default": "'auto'",
1828
+ "universal": true,
1829
+ "displayType": "\"light\" | \"dark\" | \"auto\""
1830
+ },
1831
+ {
1832
+ "name": "checked",
1833
+ "type": "undefined | false | true",
1834
+ "optional": true,
1835
+ "scalar": true,
1836
+ "description": "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.",
1837
+ "displayType": "undefined | false | true"
1838
+ },
1839
+ {
1840
+ "name": "defaultChecked",
1841
+ "type": "undefined | false | true",
1842
+ "optional": true,
1843
+ "scalar": true,
1844
+ "description": "Initial checked state on mount (uncontrolled seed). Bare attribute (`<kai-checkbox default-checked>`) turns it on.",
1845
+ "displayType": "undefined | false | true"
1846
+ },
1847
+ {
1848
+ "name": "indeterminate",
1849
+ "type": "undefined | false | true",
1850
+ "optional": true,
1851
+ "scalar": true,
1852
+ "description": "The mixed state, for a parent box whose children are partly ticked. Visual plus an accessibility hint: the box still reports `checked === false`.",
1853
+ "displayType": "undefined | false | true"
1854
+ },
1855
+ {
1856
+ "name": "disabled",
1857
+ "type": "undefined | false | true",
1858
+ "optional": true,
1859
+ "scalar": true,
1860
+ "description": "Disable interaction.",
1861
+ "displayType": "undefined | false | true"
1862
+ },
1863
+ {
1864
+ "name": "required",
1865
+ "type": "undefined | false | true",
1866
+ "optional": true,
1867
+ "scalar": true,
1868
+ "description": "Set the native `required` attribute, and nothing more. Whether an unticked box is an error is the application's rule, not the kit's.",
1869
+ "displayType": "undefined | false | true"
1870
+ },
1871
+ {
1872
+ "name": "label",
1873
+ "type": "undefined | string",
1874
+ "optional": true,
1875
+ "scalar": true,
1876
+ "description": "Accessible label. The visible text beside the box is the consumer's to render.",
1877
+ "displayType": "undefined | string"
1878
+ },
1879
+ {
1880
+ "name": "name",
1881
+ "type": "undefined | string",
1882
+ "optional": true,
1883
+ "scalar": true,
1884
+ "description": "Form-control name (paired with `value`).",
1885
+ "displayType": "undefined | string"
1886
+ },
1887
+ {
1888
+ "name": "value",
1889
+ "type": "undefined | string",
1890
+ "optional": true,
1891
+ "scalar": true,
1892
+ "description": "Submitted value when checked (paired with `name`). Defaults to `'on'`.",
1893
+ "displayType": "undefined | string"
1894
+ }
1895
+ ],
1896
+ "events": [
1897
+ {
1898
+ "name": "kai-change",
1899
+ "detail": "{ checked: false | true }",
1900
+ "description": "The box was ticked or unticked.",
1901
+ "displayDetail": "{ checked: false | true }"
1902
+ }
1903
+ ],
1904
+ "methods": [
1905
+ {
1906
+ "name": "toggle",
1907
+ "params": "",
1908
+ "returns": "void",
1909
+ "description": "Flip the box and fire `kai-change` (no-op while disabled)."
1910
+ },
1911
+ {
1912
+ "name": "focus",
1913
+ "params": "options?: FocusOptions",
1914
+ "returns": "void",
1915
+ "description": "Focus the inner input (the host element can't reach it)."
1916
+ }
1917
+ ],
1918
+ "composedFrom": [
1919
+ {
1920
+ "name": "Checkbox",
1921
+ "group": "UI",
1922
+ "storyId": "solid-advanced-primitives-checkbox--docs"
1923
+ }
1924
+ ],
1925
+ "tokens": []
1926
+ },
1927
+ {
1928
+ "tag": "kai-checkbox-group",
1929
+ "className": "KaiCheckboxGroupElement",
1930
+ "displayName": "CheckboxGroup",
1931
+ "props": [
1932
+ {
1933
+ "name": "theme",
1934
+ "type": "\"light\" | \"dark\" | \"auto\"",
1935
+ "optional": true,
1936
+ "scalar": true,
1937
+ "description": "Color mode (`auto` follows prefers-color-scheme).",
1938
+ "default": "'auto'",
1939
+ "universal": true,
1940
+ "displayType": "\"light\" | \"dark\" | \"auto\""
1941
+ },
1942
+ {
1943
+ "name": "options",
1944
+ "type": "{ value: string; label: string; description?: undefined | string; disabled?: undefined | false | true }[]",
1945
+ "optional": false,
1946
+ "scalar": false,
1947
+ "description": "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.",
1948
+ "typeName": "KaiCheckboxOption[]",
1949
+ "typeShape": "{ value: string; label: string; description?: undefined | string; disabled?: undefined | false | true }[]",
1950
+ "default": "[]",
1951
+ "typeImport": "KaiCheckboxOption",
1952
+ "displayType": "{ value: string; label: string; description?: undefined | string; disabled?: undefined | false | true }[]"
1953
+ },
1954
+ {
1955
+ "name": "value",
1956
+ "type": "undefined | string",
1957
+ "optional": true,
1958
+ "scalar": true,
1959
+ "description": "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`.",
1960
+ "displayType": "undefined | string"
1961
+ },
1962
+ {
1963
+ "name": "name",
1964
+ "type": "undefined | string",
1965
+ "optional": true,
1966
+ "scalar": true,
1967
+ "description": "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.",
1968
+ "displayType": "undefined | string"
1969
+ },
1970
+ {
1971
+ "name": "disabled",
1972
+ "type": "undefined | false | true",
1973
+ "optional": true,
1974
+ "scalar": true,
1975
+ "description": "Disable every row. Individual rows carry their own `disabled`.",
1976
+ "displayType": "undefined | false | true"
1977
+ },
1978
+ {
1979
+ "name": "label",
1980
+ "type": "undefined | string",
1981
+ "optional": true,
1982
+ "scalar": true,
1983
+ "description": "Accessible name for the group.",
1984
+ "displayType": "undefined | string"
1985
+ }
1986
+ ],
1987
+ "events": [
1988
+ {
1989
+ "name": "kai-change",
1990
+ "detail": "{ value: string; values: string[] }",
1991
+ "description": "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.",
1992
+ "displayDetail": "{ value: string; values: string[] }"
1993
+ }
1994
+ ],
1995
+ "methods": [
1996
+ {
1997
+ "name": "focus",
1998
+ "params": "options?: FocusOptions",
1999
+ "returns": "void",
2000
+ "description": "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."
2001
+ }
2002
+ ],
2003
+ "composedFrom": [
2004
+ {
2005
+ "name": "CheckboxGroup",
2006
+ "group": "UI",
2007
+ "storyId": "solid-advanced-primitives-checkboxgroup--docs"
2008
+ }
2009
+ ],
2010
+ "tokens": []
2011
+ },
1773
2012
  {
1774
2013
  "tag": "kai-checkpoint",
1775
2014
  "className": "KaiCheckpointElement",
@@ -2177,6 +2416,15 @@
2177
2416
  "default": "true",
2178
2417
  "displayType": "undefined | false | true"
2179
2418
  },
2419
+ {
2420
+ "name": "copy",
2421
+ "type": "undefined | false | true",
2422
+ "optional": true,
2423
+ "scalar": true,
2424
+ "description": "Show the copy button. **Defaults to ON**, because this element is documented as shipping one. Opt out with `copy=\"false\"` or `el.copy = false`.",
2425
+ "default": "true",
2426
+ "displayType": "undefined | false | true"
2427
+ },
2180
2428
  {
2181
2429
  "name": "proseSize",
2182
2430
  "type": "undefined | \"xs\" | \"sm\" | \"base\" | \"lg\"",
@@ -2203,6 +2451,13 @@
2203
2451
  ],
2204
2452
  "tokens": [
2205
2453
  "--color-code-foreground"
2454
+ ],
2455
+ "parts": [
2456
+ {
2457
+ "name": "copy",
2458
+ "doc": "The copy-to-clipboard button in the header row. Hide it with `copy=\"false\"` rather than CSS.",
2459
+ "recipe": "kai-code-block::part(copy) { color: var(--color-primary) }"
2460
+ }
2206
2461
  ]
2207
2462
  },
2208
2463
  {
@@ -2543,7 +2798,7 @@
2543
2798
  {
2544
2799
  "name": "kai-submit",
2545
2800
  "detail": "{ 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> }[] }",
2546
- "description": "The user submitted the composer (Enter or programmatic submit).",
2801
+ "description": "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.",
2547
2802
  "displayDetail": "{ 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> }[] }"
2548
2803
  },
2549
2804
  {
@@ -2821,9 +3076,9 @@
2821
3076
  ]
2822
3077
  },
2823
3078
  {
2824
- "tag": "kai-conversations",
2825
- "className": "KaiConversationsElement",
2826
- "displayName": "Conversations",
3079
+ "tag": "kai-conversation-item",
3080
+ "className": "KaiConversationItemElement",
3081
+ "displayName": "ConversationItem",
2827
3082
  "props": [
2828
3083
  {
2829
3084
  "name": "theme",
@@ -2836,52 +3091,172 @@
2836
3091
  "displayType": "\"light\" | \"dark\" | \"auto\""
2837
3092
  },
2838
3093
  {
2839
- "name": "groups",
2840
- "type": "undefined | { id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string }[]",
2841
- "optional": true,
2842
- "scalar": false,
2843
- "description": "The list's section headers (`{ id, name, sortOrder, createdAt }`), rendered in array order. A group carries no conversations of its own; it is matched against `conversations` by id, so the two props are complementary rather than alternatives. Omit for an ungrouped list. Set as a JS property.",
2844
- "typeName": "ConversationGroup[]",
2845
- "typeShape": "{ id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string }[]",
2846
- "default": "[]",
2847
- "typeImport": "ConversationGroup",
2848
- "displayType": "undefined | { id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string }[]"
2849
- },
2850
- {
2851
- "name": "conversations",
2852
- "type": "undefined | { id: string; title: string; groupId?: undefined | string; scope: { type: \"document\" | \"collection\"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | \"transcript\" | \"markdown\"; dateRange?: undefined | { from: string; to: string } } }; messageCount: number; lastMessageAt: string; updatedAt: string; trailing?: undefined | string }[]",
2853
- "optional": true,
2854
- "scalar": false,
2855
- "description": "Every conversation the list renders, flat. Each one is filed under the group whose `id` equals its `groupId`; one with no `groupId`, or with a `groupId` matching no entry in `groups`, falls into a trailing \"Ungrouped\" section, so nothing you pass in is ever dropped. There is no recency bucketing. Set as a JS property. Omit to supply them as `<kai-conversation>` light-DOM children instead, or for the empty state.",
2856
- "typeName": "ConversationSummary[]",
2857
- "typeShape": "{ id: string; title: string; groupId?: undefined | string; scope: { type: \"document\" | \"collection\"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | \"transcript\" | \"markdown\"; dateRange?: undefined | { from: string; to: string } } }; messageCount: number; lastMessageAt: string; updatedAt: string; trailing?: undefined | string }[]",
2858
- "default": "[]",
2859
- "typeImport": "ConversationSummary",
2860
- "displayType": "undefined | { id: string; title: string; groupId?: undefined | string; scope: { type: \"document\" | \"collection\"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | \"transcript\" | \"markdown\"; dateRange?: undefined | { from: string; to: string } } }; messageCount: number; lastMessageAt: string; updatedAt: string; trailing?: undefined | string }[]"
2861
- },
2862
- {
2863
- "name": "activeId",
3094
+ "name": "conversationId",
2864
3095
  "type": "undefined | string",
2865
3096
  "optional": true,
2866
3097
  "scalar": true,
2867
- "description": "The id of the currently-open conversation, highlighted in the list.",
3098
+ "description": "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.",
2868
3099
  "displayType": "undefined | string"
2869
3100
  },
2870
3101
  {
2871
- "name": "collapsed",
3102
+ "name": "active",
2872
3103
  "type": "undefined | false | true",
2873
3104
  "optional": true,
2874
3105
  "scalar": true,
2875
- "description": "Controlled collapsed state. Set as a JS property (`el.collapsed = true`) to drive the rail from your app, updating it in response to `kai-collapse-toggle`. Omit for uncontrolled (the element manages it). Collapsed shrinks the rail to a floating reopen button.",
3106
+ "description": "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.",
2876
3107
  "displayType": "undefined | false | true"
2877
3108
  },
2878
3109
  {
2879
- "name": "defaultCollapsed",
3110
+ "name": "compact",
3111
+ "type": "undefined | false | true",
3112
+ "optional": true,
3113
+ "scalar": true,
3114
+ "description": "Dense single-line row padding.",
3115
+ "displayType": "undefined | false | true"
3116
+ }
3117
+ ],
3118
+ "events": [
3119
+ {
3120
+ "name": "kai-select",
3121
+ "detail": "{ id: string }",
3122
+ "description": "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.",
3123
+ "displayDetail": "{ id: string }"
3124
+ }
3125
+ ],
3126
+ "methods": [],
3127
+ "composedFrom": [
3128
+ {
3129
+ "name": "SlottedConversationItem",
3130
+ "group": "Components",
3131
+ "storyId": "solid-advanced-elements-slottedconversationitem--docs"
3132
+ }
3133
+ ],
3134
+ "tokens": [],
3135
+ "slots": [
3136
+ {
3137
+ "name": "",
3138
+ "mode": "inject",
3139
+ "doc": "The row title. `leading`, `meta` and `menu` are the named regions around it."
3140
+ },
3141
+ {
3142
+ "name": "leading",
3143
+ "mode": "inject",
3144
+ "part": true,
3145
+ "doc": "Leading region before the title (an icon or avatar)."
3146
+ },
3147
+ {
3148
+ "name": "meta",
3149
+ "mode": "inject",
3150
+ "part": true,
3151
+ "doc": "Meta region under the title (a timestamp or status line)."
3152
+ },
3153
+ {
3154
+ "name": "menu",
3155
+ "mode": "inject",
3156
+ "part": true,
3157
+ "doc": "Your own row menu (a popover trigger). Never selects the row."
3158
+ }
3159
+ ],
3160
+ "parts": [
3161
+ {
3162
+ "name": "body",
3163
+ "doc": "The activation surface inside the row (button role; carries aria-current and the roving tabindex). The focus ring paints here.",
3164
+ "recipe": "kai-conversation-item::part(body) { outline-offset: 2px }"
3165
+ },
3166
+ {
3167
+ "name": "row",
3168
+ "doc": "The whole row surface. Carries `data-active` while selected.",
3169
+ "recipe": "kai-conversation-item::part(row) { border-radius: 0.5rem }"
3170
+ },
3171
+ {
3172
+ "name": "title",
3173
+ "doc": "The title line (the default slot renders inside it).",
3174
+ "recipe": "kai-conversation-item::part(title) { font-weight: 600 }"
3175
+ },
3176
+ {
3177
+ "name": "leading",
3178
+ "doc": "Leading region before the title (an icon or avatar)."
3179
+ },
3180
+ {
3181
+ "name": "meta",
3182
+ "doc": "Meta region under the title (a timestamp or status line)."
3183
+ },
3184
+ {
3185
+ "name": "menu",
3186
+ "doc": "Your own row menu (a popover trigger). Never selects the row."
3187
+ }
3188
+ ]
3189
+ },
3190
+ {
3191
+ "tag": "kai-conversations",
3192
+ "className": "KaiConversationsElement",
3193
+ "displayName": "Conversations",
3194
+ "props": [
3195
+ {
3196
+ "name": "theme",
3197
+ "type": "\"light\" | \"dark\" | \"auto\"",
3198
+ "optional": true,
3199
+ "scalar": true,
3200
+ "description": "Color mode (`auto` follows prefers-color-scheme).",
3201
+ "default": "'auto'",
3202
+ "universal": true,
3203
+ "displayType": "\"light\" | \"dark\" | \"auto\""
3204
+ },
3205
+ {
3206
+ "name": "groups",
3207
+ "type": "undefined | { id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string }[]",
3208
+ "optional": true,
3209
+ "scalar": false,
3210
+ "description": "The list's section headers (`{ id, name, sortOrder, createdAt }`), rendered in array order. A group carries no conversations of its own; it is matched against `conversations` by id, so the two props are complementary rather than alternatives. Omit for an ungrouped list. Set as a JS property.",
3211
+ "typeName": "ConversationGroup[]",
3212
+ "typeShape": "{ id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string }[]",
3213
+ "default": "[]",
3214
+ "typeImport": "ConversationGroup",
3215
+ "displayType": "undefined | { id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string }[]"
3216
+ },
3217
+ {
3218
+ "name": "conversations",
3219
+ "type": "undefined | { id: string; title: string; groupId?: undefined | string; scope?: undefined | { type: \"document\" | \"collection\"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | \"transcript\" | \"markdown\"; dateRange?: undefined | { from: string; to: string } } }; messageCount: number; lastMessageAt?: undefined | string; updatedAt: string; trailing?: undefined | string }[]",
3220
+ "optional": true,
3221
+ "scalar": false,
3222
+ "description": "Every conversation the list renders, flat. Each one is filed under the group whose `id` equals its `groupId`; one with no `groupId`, or with a `groupId` matching no entry in `groups`, falls into a trailing \"Ungrouped\" section, so nothing you pass in is ever dropped. There is no recency bucketing. Set as a JS property. Omit to supply them as `<kai-conversation>` light-DOM children instead, or for the empty state. A search query that matches nothing shows a visible \"No conversations match your search\" state, distinct from the zero-conversations empty state. Slotted `<kai-conversation-item>` children switch the list into item mode instead: your own rows win and this array is not rendered.",
3223
+ "typeName": "ConversationSummary[]",
3224
+ "typeShape": "{ id: string; title: string; groupId?: undefined | string; scope?: undefined | { type: \"document\" | \"collection\"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | \"transcript\" | \"markdown\"; dateRange?: undefined | { from: string; to: string } } }; messageCount: number; lastMessageAt?: undefined | string; updatedAt: string; trailing?: undefined | string }[]",
3225
+ "default": "[]",
3226
+ "typeImport": "ConversationSummary",
3227
+ "displayType": "undefined | { id: string; title: string; groupId?: undefined | string; scope?: undefined | { type: \"document\" | \"collection\"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | \"transcript\" | \"markdown\"; dateRange?: undefined | { from: string; to: string } } }; messageCount: number; lastMessageAt?: undefined | string; updatedAt: string; trailing?: undefined | string }[]"
3228
+ },
3229
+ {
3230
+ "name": "activeId",
3231
+ "type": "undefined | string",
3232
+ "optional": true,
3233
+ "scalar": true,
3234
+ "description": "The id of the currently-open conversation, highlighted in the list.",
3235
+ "displayType": "undefined | string"
3236
+ },
3237
+ {
3238
+ "name": "collapsed",
3239
+ "type": "undefined | false | true",
3240
+ "optional": true,
3241
+ "scalar": true,
3242
+ "description": "Controlled collapsed state. Set as a JS property (`el.collapsed = true`) to drive the rail from your app, updating it in response to `kai-collapse-toggle`. Omit for uncontrolled (the element manages it). Collapsed shrinks the rail to a floating reopen button.",
3243
+ "displayType": "undefined | false | true"
3244
+ },
3245
+ {
3246
+ "name": "defaultCollapsed",
2880
3247
  "type": "undefined | false | true",
2881
3248
  "optional": true,
2882
3249
  "scalar": true,
2883
3250
  "description": "Initial collapsed state when uncontrolled (default false). Use the `default-collapsed` attribute to start collapsed in plain HTML.",
2884
3251
  "displayType": "undefined | false | true"
3252
+ },
3253
+ {
3254
+ "name": "compact",
3255
+ "type": "undefined | false | true",
3256
+ "optional": true,
3257
+ "scalar": true,
3258
+ "description": "Dense single-line rows (a leading dot + title, no message count).",
3259
+ "displayType": "undefined | false | true"
2885
3260
  }
2886
3261
  ],
2887
3262
  "events": [
@@ -2894,7 +3269,7 @@
2894
3269
  {
2895
3270
  "name": "kai-conversation-select",
2896
3271
  "detail": "{ id: string }",
2897
- "description": "A conversation was selected.",
3272
+ "description": "A conversation was selected. The selection event in BOTH modes: a batteries data row, or an activated `<kai-conversation-item>` child (click, Enter or Space).",
2898
3273
  "displayDetail": "{ id: string }"
2899
3274
  },
2900
3275
  {
@@ -2978,10 +3353,15 @@
2978
3353
  "id"
2979
3354
  ],
2980
3355
  "text": true,
2981
- "description": "Parse a single light-DOM `<kai-conversation>` element into a `ConversationSummary`. Attribute mapping: - `id` → ConversationSummary.id - `group-id` → ConversationSummary.groupId (optional) - textContent → ConversationSummary.title Required fields not expressible as HTML attributes (`scope`, `messageCount`, `lastMessageAt`, `updatedAt`) receive safe defaults so the rendered list item is fully functional with just `id` + title text."
3356
+ "description": "Parse a single light-DOM `<kai-conversation>` element into a `ConversationSummary`. Attribute mapping: - `id` → ConversationSummary.id - `group-id` → ConversationSummary.groupId (optional) - textContent → ConversationSummary.title Fields not expressible as HTML attributes are NOT fabricated: the optional `scope` and `lastMessageAt` stay absent, and the required `messageCount`/`updatedAt` get honest defaults zero messages, and an empty `updatedAt` from which no trailing relative time is derived (the epoch it used to fabricate rendered a bogus \"many days ago\" on every declarative row)."
2982
3357
  }
2983
3358
  ],
2984
3359
  "slots": [
3360
+ {
3361
+ "name": "",
3362
+ "mode": "inject",
3363
+ "doc": "Your own `<kai-conversation-item>` rows (item mode: the consumer-owned loop). Data rows do not render while any are present."
3364
+ },
2985
3365
  {
2986
3366
  "name": "header",
2987
3367
  "mode": "replace",
@@ -3003,6 +3383,11 @@
3003
3383
  "name": "trailing",
3004
3384
  "doc": "The right-aligned trailing text on each conversation row (a count, status, or relative time). Set it per item via the `trailing` field; otherwise a short auto relative time is derived from `updatedAt`. Recolor or resize it from outside.",
3005
3385
  "recipe": "kai-conversations::part(trailing) { color: var(--color-primary); font-variant-numeric: tabular-nums }"
3386
+ },
3387
+ {
3388
+ "name": "items",
3389
+ "doc": "The item-mode listbox region wrapping your slotted `<kai-conversation-item>` children.",
3390
+ "recipe": "kai-conversations::part(items) { gap: 2px }"
3006
3391
  }
3007
3392
  ]
3008
3393
  },
@@ -3036,6 +3421,15 @@
3036
3421
  "scalar": true,
3037
3422
  "description": "Initial open state on mount (uncontrolled seed).",
3038
3423
  "displayType": "undefined | false | true"
3424
+ },
3425
+ {
3426
+ "name": "label",
3427
+ "type": "undefined | string",
3428
+ "optional": true,
3429
+ "scalar": true,
3430
+ "description": "Accessible name for the modal, used when no `header` slot is projected: `<kai-dialog label=\"Delete workspace\">`. A projected `header` WINS over this (it becomes `aria-labelledby`), because ARIA resolves `aria-labelledby` ahead of `aria-label` and the visible heading is the name both a sighted and a screen-reader user can be talked through. Defaults to `Dialog` so a modal is never nameless.",
3431
+ "default": "DEFAULT_LABEL",
3432
+ "displayType": "undefined | string"
3039
3433
  }
3040
3434
  ],
3041
3435
  "events": [
@@ -3126,9 +3520,9 @@
3126
3520
  ]
3127
3521
  },
3128
3522
  {
3129
- "tag": "kai-editable-label",
3130
- "className": "KaiEditableLabelElement",
3131
- "displayName": "EditableLabel",
3523
+ "tag": "kai-dock",
3524
+ "className": "KaiDockElement",
3525
+ "displayName": "Dock",
3132
3526
  "props": [
3133
3527
  {
3134
3528
  "name": "theme",
@@ -3141,97 +3535,428 @@
3141
3535
  "displayType": "\"light\" | \"dark\" | \"auto\""
3142
3536
  },
3143
3537
  {
3144
- "name": "value",
3145
- "type": "undefined | string",
3538
+ "name": "open",
3539
+ "type": "undefined | false | true",
3146
3540
  "optional": true,
3147
3541
  "scalar": true,
3148
- "description": "The label text. Settable and reflected to the `value` attribute. Read `el.value` for live state.",
3149
- "displayType": "undefined | string"
3542
+ "description": "Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute; the element still self-manages on the launcher and Escape). Set `el.open = true`, or `<kai-dock open>`; listen for `kai-open-change`.",
3543
+ "displayType": "undefined | false | true"
3150
3544
  },
3151
3545
  {
3152
- "name": "editing",
3546
+ "name": "defaultOpen",
3153
3547
  "type": "undefined | false | true",
3154
3548
  "optional": true,
3155
3549
  "scalar": true,
3156
- "description": "Controlled edit state. `el.editing = true` opens the field; reflected to the `editing` attribute.",
3157
- "default": "false",
3550
+ "description": "Initial open state on mount (uncontrolled seed).",
3158
3551
  "displayType": "undefined | false | true"
3159
3552
  },
3160
3553
  {
3161
- "name": "placeholder",
3554
+ "name": "position",
3555
+ "type": "undefined | \"bottom-end\" | \"bottom-start\" | \"top-end\" | \"top-start\"",
3556
+ "optional": true,
3557
+ "scalar": true,
3558
+ "description": "Which corner the dock sits in. Logical, so `-end` follows the writing direction and an RTL page docks on the left. Attribute: `position`.",
3559
+ "default": "'bottom-end'",
3560
+ "displayType": "undefined | \"bottom-end\" | \"bottom-start\" | \"top-end\" | \"top-start\""
3561
+ },
3562
+ {
3563
+ "name": "label",
3162
3564
  "type": "undefined | string",
3163
3565
  "optional": true,
3164
3566
  "scalar": true,
3165
- "description": "Placeholder shown while editing / when the value is empty.",
3567
+ "description": "The widget's NAME. Derives the panel's accessible name and both launcher names (`Open ${label}` / `Close ${label}`). Defaults to `Chat`.",
3568
+ "default": "'Chat'",
3166
3569
  "displayType": "undefined | string"
3167
3570
  },
3571
+ {
3572
+ "name": "openLabel",
3573
+ "type": "undefined | string",
3574
+ "optional": true,
3575
+ "scalar": true,
3576
+ "description": "i18n override for the launcher's name while closed (default `Open ${label}`).",
3577
+ "displayType": "undefined | string"
3578
+ },
3579
+ {
3580
+ "name": "closeLabel",
3581
+ "type": "undefined | string",
3582
+ "optional": true,
3583
+ "scalar": true,
3584
+ "description": "i18n override for the launcher's name while open (default `Close ${label}`).",
3585
+ "displayType": "undefined | string"
3586
+ },
3587
+ {
3588
+ "name": "unread",
3589
+ "type": "undefined | false | true",
3590
+ "optional": true,
3591
+ "scalar": true,
3592
+ "description": "Show the unread dot. YOURS: it renders only while closed, and the dock never writes it back. Clear it in your `kai-open-change` handler.",
3593
+ "displayType": "undefined | false | true"
3594
+ },
3168
3595
  {
3169
3596
  "name": "disabled",
3170
3597
  "type": "undefined | false | true",
3171
3598
  "optional": true,
3172
3599
  "scalar": true,
3173
- "description": "Disable entering edit mode.",
3174
- "default": "false",
3600
+ "description": "Disable the launcher; `show()` and `toggle()` are gated on it.",
3601
+ "displayType": "undefined | false | true"
3602
+ },
3603
+ {
3604
+ "name": "hideClose",
3605
+ "type": "undefined | false | true",
3606
+ "optional": true,
3607
+ "scalar": true,
3608
+ "description": "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`.",
3175
3609
  "displayType": "undefined | false | true"
3610
+ },
3611
+ {
3612
+ "name": "focusOnOpen",
3613
+ "type": "undefined | \"content\" | \"panel\" | \"none\"",
3614
+ "optional": true,
3615
+ "scalar": true,
3616
+ "description": "Where focus lands on open: `content` (default, the first element you slotted), `panel`, or `none`. Attribute: `focus-on-open`.",
3617
+ "default": "'content'",
3618
+ "displayType": "undefined | \"content\" | \"panel\" | \"none\""
3176
3619
  }
3177
3620
  ],
3178
3621
  "events": [
3179
3622
  {
3180
- "name": "kai-cancel",
3181
- "detail": "Record<string, never>",
3182
- "description": "Edit was cancelled (Esc); the text is restored.",
3183
- "displayDetail": "Record<string, never>"
3184
- },
3185
- {
3186
- "name": "kai-rename",
3187
- "detail": "{ value: string }",
3188
- "description": "Committed a changed value (Enter / blur).",
3189
- "displayDetail": "{ value: string }"
3623
+ "name": "kai-open-change",
3624
+ "detail": "{ open: false | true }",
3625
+ "description": "The dock opened or closed (the launcher, Escape, a driven `open`, or a method).",
3626
+ "displayDetail": "{ open: false | true }"
3190
3627
  }
3191
3628
  ],
3192
3629
  "methods": [
3193
3630
  {
3194
- "name": "edit",
3631
+ "name": "show",
3195
3632
  "params": "",
3196
3633
  "returns": "void",
3197
- "description": "Switch the label into its editing field, which autofocuses and selects the current text. Same entry point as a user double-click, and a no-op while `disabled`. Commit with `commit()` or by blurring, abandon with `cancel()` or Escape."
3634
+ "description": "Open it programmatically (no-op while disabled)."
3198
3635
  },
3199
3636
  {
3200
- "name": "commit",
3637
+ "name": "hide",
3201
3638
  "params": "",
3202
3639
  "returns": "void",
3203
- "description": "Close the field and keep what was typed, exactly as blurring it does. `kai-rename` fires only when the text actually changed, so committing an untouched field is silent. A no-op while the field is closed."
3640
+ "description": "Close it programmatically."
3204
3641
  },
3205
3642
  {
3206
- "name": "cancel",
3643
+ "name": "toggle",
3207
3644
  "params": "",
3208
3645
  "returns": "void",
3209
- "description": "Abandon the edit, exactly as Escape does: the original text is restored, the field closes and `kai-cancel` fires. `kai-rename` never fires, even if the field was edited. Also works when `editing` was set programmatically and the field has not rendered yet."
3646
+ "description": "Flip the open state (closes while disabled)."
3647
+ },
3648
+ {
3649
+ "name": "focus",
3650
+ "params": "options?: FocusOptions",
3651
+ "returns": "void",
3652
+ "description": "Move focus to the panel while open, or to the launcher while closed."
3210
3653
  }
3211
3654
  ],
3212
3655
  "composedFrom": [
3213
3656
  {
3214
- "name": "EditableLabel",
3657
+ "name": "Dock",
3215
3658
  "group": "UI",
3216
- "storyId": "solid-advanced-primitives-editablelabel--docs"
3659
+ "storyId": "solid-advanced-primitives-dock--docs"
3660
+ },
3661
+ {
3662
+ "name": "DockCloseGlyph",
3663
+ "group": "UI",
3664
+ "storyId": "solid-advanced-primitives-dockcloseglyph--docs"
3665
+ },
3666
+ {
3667
+ "name": "DockLauncherGlyph",
3668
+ "group": "UI",
3669
+ "storyId": "solid-advanced-primitives-docklauncherglyph--docs"
3217
3670
  }
3218
3671
  ],
3219
3672
  "tokens": [],
3673
+ "slots": [
3674
+ {
3675
+ "name": "",
3676
+ "mode": "inject",
3677
+ "doc": "The panel body, the same region as `slot=\"panel\"`."
3678
+ },
3679
+ {
3680
+ "name": "panel",
3681
+ "mode": "replace",
3682
+ "part": true,
3683
+ "doc": "The panel body. ANY element: a `<kai-chat>`, a form, your own component. The dock never reads or types it, and the default slot is the same region."
3684
+ },
3685
+ {
3686
+ "name": "launcher",
3687
+ "mode": "inject",
3688
+ "doc": "Content inside the built-in button while CLOSED; defaults to a chat glyph. Text works as well as an icon: the button keeps its height and grows sideways into a pill, so a label like \"Support\" is not clipped. The BUTTON is never slotted away, because it owns aria-expanded, aria-controls, the toggle wiring and the focus return."
3689
+ },
3690
+ {
3691
+ "name": "launcher-open",
3692
+ "mode": "inject",
3693
+ "doc": "Content inside the button while OPEN; defaults to a ✕. Fill only `launcher` and that glyph stays while open rather than morphing into a built-in that clashes with it."
3694
+ }
3695
+ ],
3220
3696
  "parts": [
3221
3697
  {
3222
- "name": "text",
3223
- "doc": "The read-mode label text. Restyle its typography; it swaps to the input on edit.",
3224
- "recipe": "kai-editable-label::part(text) { font-weight: 600 }"
3698
+ "name": "launcher",
3699
+ "doc": "The launcher button pinned to the corner: a disc by default, a pill once you slot a text label. Restyle its surface or shadow; --kai-dock-launcher-size sets its height and its minimum width.",
3700
+ "recipe": "kai-dock::part(launcher) { background: var(--color-info) }"
3225
3701
  },
3226
3702
  {
3227
- "name": "input",
3228
- "doc": "The edit-mode input (the composed kai-input field).",
3229
- "recipe": "kai-editable-label::part(input) { font: inherit }"
3703
+ "name": "badge",
3704
+ "doc": "The unread dot on the launcher, rendered only while closed and only when `unread` is set. Restyle its color or size.",
3705
+ "recipe": "kai-dock::part(badge) { background: var(--color-success) }"
3706
+ },
3707
+ {
3708
+ "name": "panel",
3709
+ "doc": "The panel body. ANY element: a `<kai-chat>`, a form, your own component. The dock never reads or types it, and the default slot is the same region."
3230
3710
  }
3231
3711
  ]
3232
3712
  },
3233
3713
  {
3234
- "tag": "kai-embed",
3714
+ "tag": "kai-dropdown",
3715
+ "className": "KaiDropdownElement",
3716
+ "displayName": "Dropdown",
3717
+ "props": [
3718
+ {
3719
+ "name": "theme",
3720
+ "type": "\"light\" | \"dark\" | \"auto\"",
3721
+ "optional": true,
3722
+ "scalar": true,
3723
+ "description": "Color mode (`auto` follows prefers-color-scheme).",
3724
+ "default": "'auto'",
3725
+ "universal": true,
3726
+ "displayType": "\"light\" | \"dark\" | \"auto\""
3727
+ },
3728
+ {
3729
+ "name": "triggerIcon",
3730
+ "type": "undefined | string",
3731
+ "optional": true,
3732
+ "scalar": true,
3733
+ "description": "Built-in trigger: leading icon (a named icon like `\"plus\"`, an image URL/data-URI, or text). A slotted `slot=\"trigger\"` overrides it.",
3734
+ "displayType": "undefined | string"
3735
+ },
3736
+ {
3737
+ "name": "triggerLabel",
3738
+ "type": "undefined | string",
3739
+ "optional": true,
3740
+ "scalar": true,
3741
+ "description": "Built-in trigger: a text label. This is the trigger's VISIBLE text, so it is also its accessible name, and `label` does not override it: an accessible name that does not contain the visible text is unreachable by speech input (WCAG 2.5.3, Label in Name). Same rule `kai-menu` follows.",
3742
+ "displayType": "undefined | string"
3743
+ },
3744
+ {
3745
+ "name": "triggerIconTrailing",
3746
+ "type": "undefined | string",
3747
+ "optional": true,
3748
+ "scalar": true,
3749
+ "description": "Built-in trigger: a trailing icon (e.g. `\"chevron-down\"` for a select look).",
3750
+ "displayType": "undefined | string"
3751
+ },
3752
+ {
3753
+ "name": "label",
3754
+ "type": "undefined | string",
3755
+ "optional": true,
3756
+ "scalar": true,
3757
+ "description": "Accessible name for a trigger with no visible label. Ignored when `triggerLabel` is set, which is already the visible name. It DOES name a slotted `slot=\"trigger\"`, which is VISUAL content with the name supplied separately: the same two-slot distinction `kai-menu` documents.",
3758
+ "displayType": "undefined | string"
3759
+ },
3760
+ {
3761
+ "name": "full",
3762
+ "type": "undefined | false | true",
3763
+ "optional": true,
3764
+ "scalar": true,
3765
+ "description": "Stretch the trigger to the full width of its container (a block row). Attribute: `full`.",
3766
+ "default": "false",
3767
+ "displayType": "undefined | false | true"
3768
+ },
3769
+ {
3770
+ "name": "open",
3771
+ "type": "undefined | false | true",
3772
+ "optional": true,
3773
+ "scalar": true,
3774
+ "description": "Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute, the menu still self-manages on click/keyboard). Set `el.open = true`, or `<kai-dropdown open>`; listen for `kai-open-change`.",
3775
+ "displayType": "undefined | false | true"
3776
+ },
3777
+ {
3778
+ "name": "defaultOpen",
3779
+ "type": "undefined | false | true",
3780
+ "optional": true,
3781
+ "scalar": true,
3782
+ "description": "Initial open state on mount (uncontrolled seed).",
3783
+ "displayType": "undefined | false | true"
3784
+ },
3785
+ {
3786
+ "name": "disabled",
3787
+ "type": "undefined | false | true",
3788
+ "optional": true,
3789
+ "scalar": true,
3790
+ "description": "Disable the trigger: click/keyboard and `show()` no longer open the menu.",
3791
+ "displayType": "undefined | false | true"
3792
+ }
3793
+ ],
3794
+ "events": [
3795
+ {
3796
+ "name": "kai-open-change",
3797
+ "detail": "{ open: false | true }",
3798
+ "description": "The menu opened or closed (click, keyboard, Escape, outside-click, or a method).",
3799
+ "displayDetail": "{ open: false | true }"
3800
+ }
3801
+ ],
3802
+ "methods": [
3803
+ {
3804
+ "name": "show",
3805
+ "params": "",
3806
+ "returns": "void",
3807
+ "description": "Open it programmatically (no-op while disabled)."
3808
+ },
3809
+ {
3810
+ "name": "hide",
3811
+ "params": "",
3812
+ "returns": "void",
3813
+ "description": "Close it programmatically."
3814
+ },
3815
+ {
3816
+ "name": "toggle",
3817
+ "params": "",
3818
+ "returns": "void",
3819
+ "description": "Flip the open state (closes while disabled)."
3820
+ }
3821
+ ],
3822
+ "composedFrom": [
3823
+ {
3824
+ "name": "Dropdown",
3825
+ "group": "UI",
3826
+ "storyId": "solid-advanced-primitives-dropdown--docs"
3827
+ },
3828
+ {
3829
+ "name": "DropdownTrigger",
3830
+ "group": "UI",
3831
+ "storyId": "solid-advanced-primitives-dropdowntrigger--docs"
3832
+ },
3833
+ {
3834
+ "name": "DropdownContent",
3835
+ "group": "UI",
3836
+ "storyId": "solid-advanced-primitives-dropdowncontent--docs"
3837
+ }
3838
+ ],
3839
+ "tokens": [],
3840
+ "slots": [
3841
+ {
3842
+ "name": "",
3843
+ "mode": "inject",
3844
+ "doc": "The menu body: your own rows. Give each `role=\"menuitem\"`. The control that opens it is the `trigger` slot."
3845
+ },
3846
+ {
3847
+ "name": "trigger",
3848
+ "mode": "replace",
3849
+ "doc": "Visual content of the trigger button (an icon, text, an `<svg>`). Replaces the built-in trigger* content; name it with `label`."
3850
+ }
3851
+ ]
3852
+ },
3853
+ {
3854
+ "tag": "kai-editable-label",
3855
+ "className": "KaiEditableLabelElement",
3856
+ "displayName": "EditableLabel",
3857
+ "props": [
3858
+ {
3859
+ "name": "theme",
3860
+ "type": "\"light\" | \"dark\" | \"auto\"",
3861
+ "optional": true,
3862
+ "scalar": true,
3863
+ "description": "Color mode (`auto` follows prefers-color-scheme).",
3864
+ "default": "'auto'",
3865
+ "universal": true,
3866
+ "displayType": "\"light\" | \"dark\" | \"auto\""
3867
+ },
3868
+ {
3869
+ "name": "value",
3870
+ "type": "undefined | string",
3871
+ "optional": true,
3872
+ "scalar": true,
3873
+ "description": "The label text. Settable and reflected to the `value` attribute. Read `el.value` for live state.",
3874
+ "displayType": "undefined | string"
3875
+ },
3876
+ {
3877
+ "name": "editing",
3878
+ "type": "undefined | false | true",
3879
+ "optional": true,
3880
+ "scalar": true,
3881
+ "description": "Controlled edit state. `el.editing = true` opens the field; reflected to the `editing` attribute.",
3882
+ "default": "false",
3883
+ "displayType": "undefined | false | true"
3884
+ },
3885
+ {
3886
+ "name": "placeholder",
3887
+ "type": "undefined | string",
3888
+ "optional": true,
3889
+ "scalar": true,
3890
+ "description": "Placeholder shown while editing / when the value is empty.",
3891
+ "displayType": "undefined | string"
3892
+ },
3893
+ {
3894
+ "name": "disabled",
3895
+ "type": "undefined | false | true",
3896
+ "optional": true,
3897
+ "scalar": true,
3898
+ "description": "Disable entering edit mode.",
3899
+ "default": "false",
3900
+ "displayType": "undefined | false | true"
3901
+ }
3902
+ ],
3903
+ "events": [
3904
+ {
3905
+ "name": "kai-cancel",
3906
+ "detail": "Record<string, never>",
3907
+ "description": "Edit was cancelled (Esc); the text is restored.",
3908
+ "displayDetail": "Record<string, never>"
3909
+ },
3910
+ {
3911
+ "name": "kai-rename",
3912
+ "detail": "{ value: string }",
3913
+ "description": "Committed a changed value (Enter / blur).",
3914
+ "displayDetail": "{ value: string }"
3915
+ }
3916
+ ],
3917
+ "methods": [
3918
+ {
3919
+ "name": "edit",
3920
+ "params": "",
3921
+ "returns": "void",
3922
+ "description": "Switch the label into its editing field, which autofocuses and selects the current text. Same entry point as a user double-click, and a no-op while `disabled`. Commit with `commit()` or by blurring, abandon with `cancel()` or Escape."
3923
+ },
3924
+ {
3925
+ "name": "commit",
3926
+ "params": "",
3927
+ "returns": "void",
3928
+ "description": "Close the field and keep what was typed, exactly as blurring it does. `kai-rename` fires only when the text actually changed, so committing an untouched field is silent. A no-op while the field is closed."
3929
+ },
3930
+ {
3931
+ "name": "cancel",
3932
+ "params": "",
3933
+ "returns": "void",
3934
+ "description": "Abandon the edit, exactly as Escape does: the original text is restored, the field closes and `kai-cancel` fires. `kai-rename` never fires, even if the field was edited. Also works when `editing` was set programmatically and the field has not rendered yet."
3935
+ }
3936
+ ],
3937
+ "composedFrom": [
3938
+ {
3939
+ "name": "EditableLabel",
3940
+ "group": "UI",
3941
+ "storyId": "solid-advanced-primitives-editablelabel--docs"
3942
+ }
3943
+ ],
3944
+ "tokens": [],
3945
+ "parts": [
3946
+ {
3947
+ "name": "text",
3948
+ "doc": "The read-mode label text. Restyle its typography; it swaps to the input on edit.",
3949
+ "recipe": "kai-editable-label::part(text) { font-weight: 600 }"
3950
+ },
3951
+ {
3952
+ "name": "input",
3953
+ "doc": "The edit-mode input (the composed kai-input field).",
3954
+ "recipe": "kai-editable-label::part(input) { font: inherit }"
3955
+ }
3956
+ ]
3957
+ },
3958
+ {
3959
+ "tag": "kai-embed",
3235
3960
  "className": "KaiEmbedElement",
3236
3961
  "displayName": "Embed",
3237
3962
  "props": [
@@ -3652,14 +4377,14 @@
3652
4377
  },
3653
4378
  {
3654
4379
  "name": "data",
3655
- "type": "undefined | { type: \"object\"; title?: undefined | string; description?: undefined | string; required?: undefined | string[]; properties: Record<string, { type: \"string\" | \"number\" | \"integer\" | \"boolean\" | \"array\" | \"object\"; title?: undefined | string; description?: undefined | string; default?: unknown; enum?: undefined | unknown[]; format?: undefined | \"email\" | \"uri\" | \"url\" | \"date\" | \"date-time\" | \"time\"; minimum?: undefined | number; maximum?: undefined | number; minLength?: undefined | number; maxLength?: undefined | number; pattern?: undefined | string; minItems?: undefined | number; maxItems?: undefined | number; items?: undefined | Record<string, unknown> | { enum: unknown[] }; properties?: undefined | Record<string, Record<string, unknown>>; required?: undefined | string[]; readOnly?: undefined | false | true; \"x-kai-widget\"?: undefined | \"textarea\" | \"slider\" | \"rating\" | \"radio\" | \"select\" | \"checkbox\" | \"password\" | \"switch\"; \"x-kai-placeholder\"?: undefined | string; \"x-kai-step\"?: undefined | number }>; \"x-kai-order\"?: undefined | string[]; \"x-kai-inlineMax\"?: undefined | number; \"x-kai-submitLabel\"?: undefined | string; \"x-kai-dismissible\"?: undefined | false | true; \"x-kai-actions\"?: undefined | { id: string; label: string; variant?: undefined | \"default\" | \"ghost\" | \"outline\" }[] }",
4380
+ "type": "undefined | { type: \"object\"; title?: undefined | string; description?: undefined | string; required?: undefined | string[]; properties: Record<string, { type: \"string\" | \"number\" | \"integer\" | \"boolean\" | \"array\" | \"object\"; title?: undefined | string; description?: undefined | string; default?: unknown; enum?: undefined | unknown[]; format?: undefined | \"email\" | \"uri\" | \"url\" | \"date\" | \"date-time\" | \"time\"; minimum?: undefined | number; maximum?: undefined | number; minLength?: undefined | number; maxLength?: undefined | number; pattern?: undefined | string; minItems?: undefined | number; maxItems?: undefined | number; items?: undefined | Record<string, unknown> | { enum: unknown[] }; properties?: undefined | Record<string, Record<string, unknown>>; required?: undefined | string[]; readOnly?: undefined | false | true; \"x-kai-widget\"?: undefined | \"textarea\" | \"slider\" | \"rating\" | \"radio\" | \"select\" | \"checkbox\" | \"password\" | \"switch\"; \"x-kai-placeholder\"?: undefined | string; \"x-kai-step\"?: undefined | number; \"x-kai-format\"?: undefined | \"tel\" | \"ssn\" | \"credit-card\" | \"custom\"; \"x-kai-mask\"?: undefined | string; \"x-kai-mask-guide\"?: undefined | string }>; \"x-kai-order\"?: undefined | string[]; \"x-kai-inlineMax\"?: undefined | number; \"x-kai-submitLabel\"?: undefined | string; \"x-kai-dismissible\"?: undefined | false | true; \"x-kai-actions\"?: undefined | { id: string; label: string; variant?: undefined | \"default\" | \"ghost\" | \"outline\" }[] }",
3656
4381
  "optional": true,
3657
4382
  "scalar": false,
3658
4383
  "description": "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.",
3659
4384
  "typeName": "FormDefinition",
3660
- "typeShape": "{ type: \"object\"; title?: undefined | string; description?: undefined | string; required?: undefined | string[]; properties: Record<string, { type: \"string\" | \"number\" | \"integer\" | \"boolean\" | \"array\" | \"object\"; title?: undefined | string; description?: undefined | string; default?: unknown; enum?: undefined | unknown[]; format?: undefined | \"email\" | \"uri\" | \"url\" | \"date\" | \"date-time\" | \"time\"; minimum?: undefined | number; maximum?: undefined | number; minLength?: undefined | number; maxLength?: undefined | number; pattern?: undefined | string; minItems?: undefined | number; maxItems?: undefined | number; items?: undefined | Record<string, unknown> | { enum: unknown[] }; properties?: undefined | Record<string, Record<string, unknown>>; required?: undefined | string[]; readOnly?: undefined | false | true; \"x-kai-widget\"?: undefined | \"textarea\" | \"slider\" | \"rating\" | \"radio\" | \"select\" | \"checkbox\" | \"password\" | \"switch\"; \"x-kai-placeholder\"?: undefined | string; \"x-kai-step\"?: undefined | number }>; \"x-kai-order\"?: undefined | string[]; \"x-kai-inlineMax\"?: undefined | number; \"x-kai-submitLabel\"?: undefined | string; \"x-kai-dismissible\"?: undefined | false | true; \"x-kai-actions\"?: undefined | { id: string; label: string; variant?: undefined | \"default\" | \"ghost\" | \"outline\" }[] }",
4385
+ "typeShape": "{ type: \"object\"; title?: undefined | string; description?: undefined | string; required?: undefined | string[]; properties: Record<string, { type: \"string\" | \"number\" | \"integer\" | \"boolean\" | \"array\" | \"object\"; title?: undefined | string; description?: undefined | string; default?: unknown; enum?: undefined | unknown[]; format?: undefined | \"email\" | \"uri\" | \"url\" | \"date\" | \"date-time\" | \"time\"; minimum?: undefined | number; maximum?: undefined | number; minLength?: undefined | number; maxLength?: undefined | number; pattern?: undefined | string; minItems?: undefined | number; maxItems?: undefined | number; items?: undefined | Record<string, unknown> | { enum: unknown[] }; properties?: undefined | Record<string, Record<string, unknown>>; required?: undefined | string[]; readOnly?: undefined | false | true; \"x-kai-widget\"?: undefined | \"textarea\" | \"slider\" | \"rating\" | \"radio\" | \"select\" | \"checkbox\" | \"password\" | \"switch\"; \"x-kai-placeholder\"?: undefined | string; \"x-kai-step\"?: undefined | number; \"x-kai-format\"?: undefined | \"tel\" | \"ssn\" | \"credit-card\" | \"custom\"; \"x-kai-mask\"?: undefined | string; \"x-kai-mask-guide\"?: undefined | string }>; \"x-kai-order\"?: undefined | string[]; \"x-kai-inlineMax\"?: undefined | number; \"x-kai-submitLabel\"?: undefined | string; \"x-kai-dismissible\"?: undefined | false | true; \"x-kai-actions\"?: undefined | { id: string; label: string; variant?: undefined | \"default\" | \"ghost\" | \"outline\" }[] }",
3661
4386
  "typeImport": "FormDefinition",
3662
- "displayType": "undefined | { type: \"object\"; title?: undefined | string; description?: undefined | string; required?: undefined | string[]; properties: Record<string, { type: \"string\" | \"number\" | \"integer\" | \"boolean\" | \"array\" | \"object\"; title?: undefined | string; description?: undefined | string; default?: unknown; enum?: undefined | unknown[]; format?: undefined | \"email\" | \"uri\" | \"url\" | \"date\" | \"date-time\" | \"time\"; minimum?: undefined | number; maximum?: undefined | number; minLength?: undefined | number; maxLength?: undefined | number; pattern?: undefined | string; minItems?: undefined | number; maxItems?: undefined | number; items?: undefined | Record<string, unknown> | { enum: unknown[] }; properties?: undefined | Record<string, Record<string, unknown>>; required?: undefined | string[]; readOnly?: undefined | false | true; \"x-kai-widget\"?: undefined | \"textarea\" | \"slider\" | \"rating\" | \"radio\" | \"select\" | \"checkbox\" | \"password\" | \"switch\"; \"x-kai-placeholder\"?: undefined | string; \"x-kai-step\"?: undefined | number }>; \"x-kai-order\"?: undefined | string[]; \"x-kai-inlineMax\"?: undefined | number; \"x-kai-submitLabel\"?: undefined | string; \"x-kai-dismissible\"?: undefined | false | true; \"x-kai-actions\"?: undefined | { id: string; label: string; variant?: undefined | \"default\" | \"ghost\" | \"outline\" }[] }"
4387
+ "displayType": "undefined | { type: \"object\"; title?: undefined | string; description?: undefined | string; required?: undefined | string[]; properties: Record<string, { type: \"string\" | \"number\" | \"integer\" | \"boolean\" | \"array\" | \"object\"; title?: undefined | string; description?: undefined | string; default?: unknown; enum?: undefined | unknown[]; format?: undefined | \"email\" | \"uri\" | \"url\" | \"date\" | \"date-time\" | \"time\"; minimum?: undefined | number; maximum?: undefined | number; minLength?: undefined | number; maxLength?: undefined | number; pattern?: undefined | string; minItems?: undefined | number; maxItems?: undefined | number; items?: undefined | Record<string, unknown> | { enum: unknown[] }; properties?: undefined | Record<string, Record<string, unknown>>; required?: undefined | string[]; readOnly?: undefined | false | true; \"x-kai-widget\"?: undefined | \"textarea\" | \"slider\" | \"rating\" | \"radio\" | \"select\" | \"checkbox\" | \"password\" | \"switch\"; \"x-kai-placeholder\"?: undefined | string; \"x-kai-step\"?: undefined | number; \"x-kai-format\"?: undefined | \"tel\" | \"ssn\" | \"credit-card\" | \"custom\"; \"x-kai-mask\"?: undefined | string; \"x-kai-mask-guide\"?: undefined | string }>; \"x-kai-order\"?: undefined | string[]; \"x-kai-inlineMax\"?: undefined | number; \"x-kai-submitLabel\"?: undefined | string; \"x-kai-dismissible\"?: undefined | false | true; \"x-kai-actions\"?: undefined | { id: string; label: string; variant?: undefined | \"default\" | \"ghost\" | \"outline\" }[] }"
3663
4388
  },
3664
4389
  {
3665
4390
  "name": "cardId",
@@ -4024,7 +4749,7 @@
4024
4749
  "type": "undefined | string",
4025
4750
  "optional": true,
4026
4751
  "scalar": true,
4027
- "description": "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.",
4752
+ "description": "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`.",
4028
4753
  "displayType": "undefined | string"
4029
4754
  },
4030
4755
  {
@@ -4123,27 +4848,73 @@
4123
4848
  "scalar": true,
4124
4849
  "description": "Virtual-keyboard hint forwarded to the inner input (e.g. `numeric`, `email`).",
4125
4850
  "displayType": "undefined | string"
4126
- }
4127
- ],
4128
- "events": [
4129
- {
4130
- "name": "kai-change",
4131
- "detail": "{ value: string }",
4132
- "description": "The value was committed (blur).",
4133
- "displayDetail": "{ value: string }"
4134
4851
  },
4135
4852
  {
4136
- "name": "kai-input",
4137
- "detail": "{ value: string }",
4138
- "description": "The value changed per keystroke.",
4139
- "displayDetail": "{ value: string }"
4140
- }
4141
- ],
4142
- "methods": [
4853
+ "name": "format",
4854
+ "type": "undefined | string",
4855
+ "optional": true,
4856
+ "scalar": true,
4857
+ "description": "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.",
4858
+ "displayType": "undefined | string"
4859
+ },
4143
4860
  {
4144
- "name": "focus",
4145
- "params": "options?: FocusOptions",
4146
- "returns": "void",
4861
+ "name": "guide",
4862
+ "type": "undefined | string",
4863
+ "optional": true,
4864
+ "scalar": true,
4865
+ "description": "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.",
4866
+ "displayType": "undefined | string"
4867
+ },
4868
+ {
4869
+ "name": "semantic",
4870
+ "type": "undefined | \"credit-card\" | \"custom\" | \"ssn\" | \"tel\"",
4871
+ "optional": true,
4872
+ "scalar": true,
4873
+ "description": "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.",
4874
+ "displayType": "undefined | \"credit-card\" | \"custom\" | \"ssn\" | \"tel\""
4875
+ },
4876
+ {
4877
+ "name": "caseMode",
4878
+ "type": "undefined | \"preserve\" | \"upper\" | \"lower\"",
4879
+ "optional": true,
4880
+ "scalar": true,
4881
+ "description": "Case folding applied to typed and pasted text: `preserve` (default) · `upper` · `lower`. Attribute: `case-mode`.",
4882
+ "displayType": "undefined | \"preserve\" | \"upper\" | \"lower\""
4883
+ },
4884
+ {
4885
+ "name": "copyPolicy",
4886
+ "type": "undefined | \"formatted\" | \"canonical\" | \"obscured\" | \"blocked\"",
4887
+ "optional": true,
4888
+ "scalar": true,
4889
+ "description": "What a copy or cut of a masked field puts on the clipboard: `canonical` (default) · `formatted` · `obscured` · `blocked`. Attribute: `copy-policy`.",
4890
+ "displayType": "undefined | \"formatted\" | \"canonical\" | \"obscured\" | \"blocked\""
4891
+ }
4892
+ ],
4893
+ "events": [
4894
+ {
4895
+ "name": "kai-change",
4896
+ "detail": "{ value: string; formattedValue: string }",
4897
+ "description": "The value was committed (blur). Same detail shape as `kai-input`.",
4898
+ "displayDetail": "{ value: string; formattedValue: string }"
4899
+ },
4900
+ {
4901
+ "name": "kai-input",
4902
+ "detail": "{ value: string; formattedValue: string }",
4903
+ "description": "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.",
4904
+ "displayDetail": "{ value: string; formattedValue: string }"
4905
+ },
4906
+ {
4907
+ "name": "kai-input-rejected",
4908
+ "detail": "{ reason: \"full\" | \"wrong-class\" | \"over-capacity\" | \"format-change-clipped\"; data: string }",
4909
+ "description": "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.",
4910
+ "displayDetail": "{ reason: \"full\" | \"wrong-class\" | \"over-capacity\" | \"format-change-clipped\"; data: string }"
4911
+ }
4912
+ ],
4913
+ "methods": [
4914
+ {
4915
+ "name": "focus",
4916
+ "params": "options?: FocusOptions",
4917
+ "returns": "void",
4147
4918
  "description": "Focus the inner input (the host can't reach into the shadow root)."
4148
4919
  },
4149
4920
  {
@@ -4152,11 +4923,23 @@
4152
4923
  "returns": "void",
4153
4924
  "description": "Select the inner input's text."
4154
4925
  },
4926
+ {
4927
+ "name": "getRawValue",
4928
+ "params": "",
4929
+ "returns": "string",
4930
+ "description": "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."
4931
+ },
4932
+ {
4933
+ "name": "getFormattedValue",
4934
+ "params": "",
4935
+ "returns": "string",
4936
+ "description": "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."
4937
+ },
4155
4938
  {
4156
4939
  "name": "clear",
4157
4940
  "params": "",
4158
4941
  "returns": "void",
4159
- "description": "Empty the value and fire `kai-change` with `''`."
4942
+ "description": "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."
4160
4943
  }
4161
4944
  ],
4162
4945
  "composedFrom": [
@@ -4502,6 +5285,15 @@
4502
5285
  "description": "Accessible name for a trigger with no visible label. Ignored when `triggerLabel` is set, which is already the visible name. It DOES name a slotted `slot=\"trigger\"`, and that is a difference in what the two slots MEAN, not a limitation. `<kai-button>`'s slot IS the button's label, so text slotted there is the name and `label` steps aside. This slot is VISUAL content, a `+` or an `<svg>`, with the name supplied separately: decoration beside a name, never a second name competing with one. So `label` names the trigger here by design. Slotting a real WORD rather than a glyph makes that word a visible label, and an accessible name has to contain the visible text. Then either drop `label` or make it contain the word you slotted.",
4503
5286
  "displayType": "undefined | string"
4504
5287
  },
5288
+ {
5289
+ "name": "full",
5290
+ "type": "undefined | false | true",
5291
+ "optional": true,
5292
+ "scalar": true,
5293
+ "description": "Stretch the trigger to the full width of the menu's container (a block row), e.g. a sidebar-footer account row. Same affordance as `<kai-button full>`. Attribute: `full`.",
5294
+ "default": "false",
5295
+ "displayType": "undefined | false | true"
5296
+ },
4505
5297
  {
4506
5298
  "name": "open",
4507
5299
  "type": "undefined | false | true",
@@ -4850,6 +5642,16 @@
4850
5642
  "doc": "The citation row rendered from the message’s `source` parts: a wrapped row of chips below the bubble, never inside it. Restyle its spacing or hide it entirely from outside.",
4851
5643
  "recipe": "kai-message::part(citations) { gap: 0.5rem }"
4852
5644
  },
5645
+ {
5646
+ "name": "attachment",
5647
+ "doc": "One attachment item: the chip, row or tile, whichever variant is rendering. Restyle its background, radius or border from outside without caring which layout it is.",
5648
+ "recipe": "kai-chat::part(attachment) { border-radius: 0.25rem }"
5649
+ },
5650
+ {
5651
+ "name": "attachment-name",
5652
+ "doc": "The attachment’s filename label. Present in every variant that shows one (a grid tile omits it for an image, which is its own label). Retune its type or hide it entirely.",
5653
+ "recipe": "kai-chat::part(attachment-name) { font-size: 0.75rem }"
5654
+ },
4853
5655
  {
4854
5656
  "name": "avatar",
4855
5657
  "doc": "Replaces the built-in avatar rail with your own node. Use `avatar=\"none\"` to omit the rail and let the body span the full row."
@@ -5334,6 +6136,73 @@
5334
6136
  }
5335
6137
  ]
5336
6138
  },
6139
+ {
6140
+ "tag": "kai-pane-grid",
6141
+ "className": "KaiPaneGridElement",
6142
+ "displayName": "PaneGrid",
6143
+ "props": [
6144
+ {
6145
+ "name": "theme",
6146
+ "type": "\"light\" | \"dark\" | \"auto\"",
6147
+ "optional": true,
6148
+ "scalar": true,
6149
+ "description": "Color mode (`auto` follows prefers-color-scheme).",
6150
+ "default": "'auto'",
6151
+ "universal": true,
6152
+ "displayType": "\"light\" | \"dark\" | \"auto\""
6153
+ },
6154
+ {
6155
+ "name": "minPaneWidth",
6156
+ "type": "undefined | number",
6157
+ "optional": true,
6158
+ "scalar": true,
6159
+ "description": "Minimum width of every pane, in px, before columns drop / the grid scrolls. Defaults to `280`. Attribute: `min-pane-width`.",
6160
+ "displayType": "undefined | number"
6161
+ },
6162
+ {
6163
+ "name": "minPaneHeight",
6164
+ "type": "undefined | number",
6165
+ "optional": true,
6166
+ "scalar": true,
6167
+ "description": "Minimum height of every pane, in px, before the grid scrolls vertically. Defaults to `200`. Attribute: `min-pane-height`.",
6168
+ "displayType": "undefined | number"
6169
+ },
6170
+ {
6171
+ "name": "maxColumns",
6172
+ "type": "undefined | number",
6173
+ "optional": true,
6174
+ "scalar": true,
6175
+ "description": "Column cap when the container is wide (default `3`). Attribute: `max-columns`.",
6176
+ "displayType": "undefined | number"
6177
+ },
6178
+ {
6179
+ "name": "gap",
6180
+ "type": "undefined | string",
6181
+ "optional": true,
6182
+ "scalar": true,
6183
+ "description": "Gap between panes, any CSS length. Defaults to the kit gap (`var(--kai-pane-grid-gap, 0.5rem)`). Attribute: `gap`.",
6184
+ "displayType": "undefined | string"
6185
+ },
6186
+ {
6187
+ "name": "maximizedIndex",
6188
+ "type": "undefined | number | null",
6189
+ "optional": true,
6190
+ "scalar": false,
6191
+ "description": "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`.",
6192
+ "displayType": "undefined | number | null"
6193
+ }
6194
+ ],
6195
+ "events": [],
6196
+ "methods": [],
6197
+ "composedFrom": [
6198
+ {
6199
+ "name": "PaneGrid",
6200
+ "group": "UI",
6201
+ "storyId": "solid-advanced-primitives-panegrid--docs"
6202
+ }
6203
+ ],
6204
+ "tokens": []
6205
+ },
5337
6206
  {
5338
6207
  "tag": "kai-pane-group",
5339
6208
  "className": "KaiPaneGroupElement",
@@ -5781,11 +6650,11 @@
5781
6650
  "displayType": "undefined | \"submit\" | \"fill\""
5782
6651
  },
5783
6652
  {
5784
- "name": "search",
6653
+ "name": "webSearch",
5785
6654
  "type": "undefined | false | true",
5786
6655
  "optional": true,
5787
6656
  "scalar": true,
5788
- "description": "Show a Search (Globe) button in the left toolbar; clicking it fires a `search` event.",
6657
+ "description": "Show a web-search (Globe) button in the left toolbar; clicking it fires a `kai-web-search` event. Attribute: `web-search`.",
5789
6658
  "default": "false",
5790
6659
  "displayType": "undefined | false | true"
5791
6660
  },
@@ -5830,7 +6699,7 @@
5830
6699
  "type": "undefined | { id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[]",
5831
6700
  "optional": true,
5832
6701
  "scalar": false,
5833
- "description": "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).",
6702
+ "description": "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.)",
5834
6703
  "typeName": "AttachmentData[]",
5835
6704
  "typeShape": "{ id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[]",
5836
6705
  "typeImport": "AttachmentData",
@@ -5863,12 +6732,6 @@
5863
6732
  "description": "The staged attachments changed: a file was added (via the paperclip) or removed (per-chip ×). Carries the full current list so a consumer can react in real time (validate, show upload progress, toggle the send button).",
5864
6733
  "displayDetail": "{ attachments: { id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[] }"
5865
6734
  },
5866
- {
5867
- "name": "kai-search",
5868
- "detail": "Record<string, never>",
5869
- "description": "The Search (Globe) toolbar button was clicked.",
5870
- "displayDetail": "Record<string, never>"
5871
- },
5872
6735
  {
5873
6736
  "name": "kai-stop",
5874
6737
  "detail": "Record<string, never>",
@@ -5878,7 +6741,7 @@
5878
6741
  {
5879
6742
  "name": "kai-submit",
5880
6743
  "detail": "{ 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 }[] }",
5881
- "description": "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.",
6744
+ "description": "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.",
5882
6745
  "displayDetail": "{ 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 }[] }"
5883
6746
  },
5884
6747
  {
@@ -5904,6 +6767,12 @@
5904
6767
  "detail": "Record<string, never>",
5905
6768
  "description": "The Voice (Mic) toolbar button was clicked.",
5906
6769
  "displayDetail": "Record<string, never>"
6770
+ },
6771
+ {
6772
+ "name": "kai-web-search",
6773
+ "detail": "Record<string, never>",
6774
+ "description": "The web-search (Globe) toolbar button was clicked.",
6775
+ "displayDetail": "Record<string, never>"
5907
6776
  }
5908
6777
  ],
5909
6778
  "methods": [
@@ -6028,6 +6897,91 @@
6028
6897
  }
6029
6898
  ]
6030
6899
  },
6900
+ {
6901
+ "tag": "kai-radio-group",
6902
+ "className": "KaiRadioGroupElement",
6903
+ "displayName": "RadioGroup",
6904
+ "props": [
6905
+ {
6906
+ "name": "theme",
6907
+ "type": "\"light\" | \"dark\" | \"auto\"",
6908
+ "optional": true,
6909
+ "scalar": true,
6910
+ "description": "Color mode (`auto` follows prefers-color-scheme).",
6911
+ "default": "'auto'",
6912
+ "universal": true,
6913
+ "displayType": "\"light\" | \"dark\" | \"auto\""
6914
+ },
6915
+ {
6916
+ "name": "options",
6917
+ "type": "{ value: string; label: string; description?: undefined | string; disabled?: undefined | false | true }[]",
6918
+ "optional": false,
6919
+ "scalar": false,
6920
+ "description": "The choices, top to bottom. Set as a JS PROPERTY (array), never an attribute.",
6921
+ "typeName": "KaiRadioOption[]",
6922
+ "typeShape": "{ value: string; label: string; description?: undefined | string; disabled?: undefined | false | true }[]",
6923
+ "default": "[]",
6924
+ "typeImport": "KaiRadioOption",
6925
+ "displayType": "{ value: string; label: string; description?: undefined | string; disabled?: undefined | false | true }[]"
6926
+ },
6927
+ {
6928
+ "name": "value",
6929
+ "type": "undefined | string",
6930
+ "optional": true,
6931
+ "scalar": true,
6932
+ "description": "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.",
6933
+ "displayType": "undefined | string"
6934
+ },
6935
+ {
6936
+ "name": "name",
6937
+ "type": "undefined | string",
6938
+ "optional": true,
6939
+ "scalar": true,
6940
+ "description": "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.",
6941
+ "displayType": "undefined | string"
6942
+ },
6943
+ {
6944
+ "name": "disabled",
6945
+ "type": "undefined | false | true",
6946
+ "optional": true,
6947
+ "scalar": true,
6948
+ "description": "Disable every row. Individual rows carry their own `disabled`.",
6949
+ "displayType": "undefined | false | true"
6950
+ },
6951
+ {
6952
+ "name": "label",
6953
+ "type": "undefined | string",
6954
+ "optional": true,
6955
+ "scalar": true,
6956
+ "description": "Accessible name for the group.",
6957
+ "displayType": "undefined | string"
6958
+ }
6959
+ ],
6960
+ "events": [
6961
+ {
6962
+ "name": "kai-change",
6963
+ "detail": "{ value: string }",
6964
+ "description": "A row was chosen.",
6965
+ "displayDetail": "{ value: string }"
6966
+ }
6967
+ ],
6968
+ "methods": [
6969
+ {
6970
+ "name": "focus",
6971
+ "params": "options?: FocusOptions",
6972
+ "returns": "void",
6973
+ "description": "Focus the group's tab stop. That is the selected radio, or the first row when nothing is selected yet."
6974
+ }
6975
+ ],
6976
+ "composedFrom": [
6977
+ {
6978
+ "name": "RadioGroup",
6979
+ "group": "UI",
6980
+ "storyId": "solid-advanced-primitives-radiogroup--docs"
6981
+ }
6982
+ ],
6983
+ "tokens": []
6984
+ },
6031
6985
  {
6032
6986
  "tag": "kai-reasoning",
6033
6987
  "className": "KaiReasoningElement",
@@ -6814,6 +7768,22 @@
6814
7768
  "description": "Button size token. Defaults to `'icon'` (square).",
6815
7769
  "default": "'icon'",
6816
7770
  "displayType": "undefined | \"sm\" | \"md\" | \"lg\" | \"icon\" | \"icon-sm\""
7771
+ },
7772
+ {
7773
+ "name": "label",
7774
+ "type": "undefined | string",
7775
+ "optional": true,
7776
+ "scalar": true,
7777
+ "description": "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'`.",
7778
+ "displayType": "undefined | string"
7779
+ },
7780
+ {
7781
+ "name": "showLabel",
7782
+ "type": "undefined | false | true",
7783
+ "optional": true,
7784
+ "scalar": true,
7785
+ "description": "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.",
7786
+ "displayType": "undefined | false | true"
6817
7787
  }
6818
7788
  ],
6819
7789
  "events": [
@@ -7048,9 +8018,9 @@
7048
8018
  ]
7049
8019
  },
7050
8020
  {
7051
- "tag": "kai-separator",
7052
- "className": "KaiSeparatorElement",
7053
- "displayName": "Separator",
8021
+ "tag": "kai-select",
8022
+ "className": "KaiSelectElement",
8023
+ "displayName": "Select",
7054
8024
  "props": [
7055
8025
  {
7056
8026
  "name": "theme",
@@ -7063,71 +8033,188 @@
7063
8033
  "displayType": "\"light\" | \"dark\" | \"auto\""
7064
8034
  },
7065
8035
  {
7066
- "name": "orientation",
7067
- "type": "undefined | \"horizontal\" | \"vertical\"",
7068
- "optional": true,
7069
- "scalar": true,
7070
- "description": "`horizontal` (default, block + full-width) or `vertical` (a rule inside a flex/grid row, stretching to the row height).",
7071
- "default": "'horizontal'",
7072
- "displayType": "undefined | \"horizontal\" | \"vertical\""
7073
- }
7074
- ],
7075
- "events": [],
7076
- "methods": [],
7077
- "composedFrom": [
7078
- {
7079
- "name": "Separator",
7080
- "group": "UI",
7081
- "storyId": "solid-advanced-primitives-separator--docs"
7082
- }
7083
- ],
7084
- "tokens": [],
7085
- "parts": [
7086
- {
7087
- "name": "separator",
7088
- "doc": "The divider line. Restyle its color, thickness, or inset from outside.",
7089
- "recipe": "kai-separator::part(separator) { background: var(--color-border) }"
7090
- }
7091
- ]
7092
- },
7093
- {
7094
- "tag": "kai-setting-item",
7095
- "className": "KaiSettingItemElement",
7096
- "displayName": "SettingItem",
7097
- "props": [
7098
- {
7099
- "name": "theme",
7100
- "type": "\"light\" | \"dark\" | \"auto\"",
7101
- "optional": true,
7102
- "scalar": true,
7103
- "description": "Color mode (`auto` follows prefers-color-scheme).",
7104
- "default": "'auto'",
7105
- "universal": true,
7106
- "displayType": "\"light\" | \"dark\" | \"auto\""
8036
+ "name": "options",
8037
+ "type": "{ value: string; label?: undefined | string; disabled?: undefined | false | true }[]",
8038
+ "optional": false,
8039
+ "scalar": false,
8040
+ "description": "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.",
8041
+ "typeName": "KaiSelectOption[]",
8042
+ "typeShape": "{ value: string; label?: undefined | string; disabled?: undefined | false | true }[]",
8043
+ "default": "[]",
8044
+ "typeImport": "KaiSelectOption",
8045
+ "displayType": "{ value: string; label?: undefined | string; disabled?: undefined | false | true }[]"
7107
8046
  },
7108
8047
  {
7109
- "name": "label",
8048
+ "name": "value",
7110
8049
  "type": "undefined | string",
7111
8050
  "optional": true,
7112
8051
  "scalar": true,
7113
- "description": "Row label (primary text). Attribute: `label`.",
7114
- "default": "''",
8052
+ "description": "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.",
7115
8053
  "displayType": "undefined | string"
7116
8054
  },
7117
8055
  {
7118
- "name": "description",
8056
+ "name": "placeholder",
7119
8057
  "type": "undefined | string",
7120
8058
  "optional": true,
7121
8059
  "scalar": true,
7122
- "description": "Optional secondary description under the label. Attribute: `description`.",
8060
+ "description": "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.",
7123
8061
  "displayType": "undefined | string"
7124
- }
7125
- ],
7126
- "events": [],
7127
- "methods": [],
7128
- "composedFrom": [
8062
+ },
7129
8063
  {
7130
- "name": "SettingItem",
8064
+ "name": "multiple",
8065
+ "type": "undefined | false | true",
8066
+ "optional": true,
8067
+ "scalar": true,
8068
+ "description": "Allow more than one selection. Turns the control into the platform's list box, so the kit's chevron is not drawn.",
8069
+ "displayType": "undefined | false | true"
8070
+ },
8071
+ {
8072
+ "name": "invalid",
8073
+ "type": "undefined | false | true",
8074
+ "optional": true,
8075
+ "scalar": true,
8076
+ "description": "Force the invalid (destructive-border) state.",
8077
+ "displayType": "undefined | false | true"
8078
+ },
8079
+ {
8080
+ "name": "disabled",
8081
+ "type": "undefined | false | true",
8082
+ "optional": true,
8083
+ "scalar": true,
8084
+ "description": "Disable interaction.",
8085
+ "displayType": "undefined | false | true"
8086
+ },
8087
+ {
8088
+ "name": "required",
8089
+ "type": "undefined | false | true",
8090
+ "optional": true,
8091
+ "scalar": true,
8092
+ "description": "Set the native `required` attribute, and nothing more. Whether an empty select is an error is the application's rule, not the kit's.",
8093
+ "displayType": "undefined | false | true"
8094
+ },
8095
+ {
8096
+ "name": "label",
8097
+ "type": "undefined | string",
8098
+ "optional": true,
8099
+ "scalar": true,
8100
+ "description": "Accessible label for the control.",
8101
+ "displayType": "undefined | string"
8102
+ },
8103
+ {
8104
+ "name": "name",
8105
+ "type": "undefined | string",
8106
+ "optional": true,
8107
+ "scalar": true,
8108
+ "description": "Form-control name, for a native form submit.",
8109
+ "displayType": "undefined | string"
8110
+ }
8111
+ ],
8112
+ "events": [
8113
+ {
8114
+ "name": "kai-change",
8115
+ "detail": "{ value: string; values: string[] }",
8116
+ "description": "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.",
8117
+ "displayDetail": "{ value: string; values: string[] }"
8118
+ }
8119
+ ],
8120
+ "methods": [
8121
+ {
8122
+ "name": "focus",
8123
+ "params": "options?: FocusOptions",
8124
+ "returns": "void",
8125
+ "description": "Focus the inner select (the host element can't reach it)."
8126
+ }
8127
+ ],
8128
+ "composedFrom": [
8129
+ {
8130
+ "name": "Select",
8131
+ "group": "UI",
8132
+ "storyId": "solid-advanced-primitives-select--docs"
8133
+ }
8134
+ ],
8135
+ "tokens": []
8136
+ },
8137
+ {
8138
+ "tag": "kai-separator",
8139
+ "className": "KaiSeparatorElement",
8140
+ "displayName": "Separator",
8141
+ "props": [
8142
+ {
8143
+ "name": "theme",
8144
+ "type": "\"light\" | \"dark\" | \"auto\"",
8145
+ "optional": true,
8146
+ "scalar": true,
8147
+ "description": "Color mode (`auto` follows prefers-color-scheme).",
8148
+ "default": "'auto'",
8149
+ "universal": true,
8150
+ "displayType": "\"light\" | \"dark\" | \"auto\""
8151
+ },
8152
+ {
8153
+ "name": "orientation",
8154
+ "type": "undefined | \"horizontal\" | \"vertical\"",
8155
+ "optional": true,
8156
+ "scalar": true,
8157
+ "description": "`horizontal` (default, block + full-width) or `vertical` (a rule inside a flex/grid row, stretching to the row height).",
8158
+ "default": "'horizontal'",
8159
+ "displayType": "undefined | \"horizontal\" | \"vertical\""
8160
+ }
8161
+ ],
8162
+ "events": [],
8163
+ "methods": [],
8164
+ "composedFrom": [
8165
+ {
8166
+ "name": "Separator",
8167
+ "group": "UI",
8168
+ "storyId": "solid-advanced-primitives-separator--docs"
8169
+ }
8170
+ ],
8171
+ "tokens": [],
8172
+ "parts": [
8173
+ {
8174
+ "name": "separator",
8175
+ "doc": "The divider line. Restyle its color, thickness, or inset from outside.",
8176
+ "recipe": "kai-separator::part(separator) { background: var(--color-border) }"
8177
+ }
8178
+ ]
8179
+ },
8180
+ {
8181
+ "tag": "kai-setting-item",
8182
+ "className": "KaiSettingItemElement",
8183
+ "displayName": "SettingItem",
8184
+ "props": [
8185
+ {
8186
+ "name": "theme",
8187
+ "type": "\"light\" | \"dark\" | \"auto\"",
8188
+ "optional": true,
8189
+ "scalar": true,
8190
+ "description": "Color mode (`auto` follows prefers-color-scheme).",
8191
+ "default": "'auto'",
8192
+ "universal": true,
8193
+ "displayType": "\"light\" | \"dark\" | \"auto\""
8194
+ },
8195
+ {
8196
+ "name": "label",
8197
+ "type": "undefined | string",
8198
+ "optional": true,
8199
+ "scalar": true,
8200
+ "description": "Row label (primary text). Attribute: `label`.",
8201
+ "default": "''",
8202
+ "displayType": "undefined | string"
8203
+ },
8204
+ {
8205
+ "name": "description",
8206
+ "type": "undefined | string",
8207
+ "optional": true,
8208
+ "scalar": true,
8209
+ "description": "Optional secondary description under the label. Attribute: `description`.",
8210
+ "displayType": "undefined | string"
8211
+ }
8212
+ ],
8213
+ "events": [],
8214
+ "methods": [],
8215
+ "composedFrom": [
8216
+ {
8217
+ "name": "SettingItem",
7131
8218
  "group": "UI",
7132
8219
  "storyId": "solid-advanced-primitives-settingitem--docs"
7133
8220
  }
@@ -7332,6 +8419,117 @@
7332
8419
  }
7333
8420
  ]
7334
8421
  },
8422
+ {
8423
+ "tag": "kai-slider",
8424
+ "className": "KaiSliderElement",
8425
+ "displayName": "Slider",
8426
+ "props": [
8427
+ {
8428
+ "name": "theme",
8429
+ "type": "\"light\" | \"dark\" | \"auto\"",
8430
+ "optional": true,
8431
+ "scalar": true,
8432
+ "description": "Color mode (`auto` follows prefers-color-scheme).",
8433
+ "default": "'auto'",
8434
+ "universal": true,
8435
+ "displayType": "\"light\" | \"dark\" | \"auto\""
8436
+ },
8437
+ {
8438
+ "name": "min",
8439
+ "type": "undefined | number",
8440
+ "optional": true,
8441
+ "scalar": true,
8442
+ "description": "Lowest selectable value. Required: a range with no bounds is a guess, and the guess belongs to whoever knows what the number means.",
8443
+ "displayType": "undefined | number"
8444
+ },
8445
+ {
8446
+ "name": "max",
8447
+ "type": "undefined | number",
8448
+ "optional": true,
8449
+ "scalar": true,
8450
+ "description": "Highest selectable value. Required, for the same reason as `min`.",
8451
+ "displayType": "undefined | number"
8452
+ },
8453
+ {
8454
+ "name": "step",
8455
+ "type": "undefined | number | \"any\"",
8456
+ "optional": true,
8457
+ "scalar": true,
8458
+ "description": "Granularity. Omitted means the native default of 1; `any` means continuous.",
8459
+ "displayType": "undefined | number | \"any\""
8460
+ },
8461
+ {
8462
+ "name": "value",
8463
+ "type": "undefined | number",
8464
+ "optional": true,
8465
+ "scalar": true,
8466
+ "description": "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.",
8467
+ "displayType": "undefined | number"
8468
+ },
8469
+ {
8470
+ "name": "disabled",
8471
+ "type": "undefined | false | true",
8472
+ "optional": true,
8473
+ "scalar": true,
8474
+ "description": "Disable interaction.",
8475
+ "displayType": "undefined | false | true"
8476
+ },
8477
+ {
8478
+ "name": "label",
8479
+ "type": "undefined | string",
8480
+ "optional": true,
8481
+ "scalar": true,
8482
+ "description": "Accessible label for the slider.",
8483
+ "displayType": "undefined | string"
8484
+ },
8485
+ {
8486
+ "name": "name",
8487
+ "type": "undefined | string",
8488
+ "optional": true,
8489
+ "scalar": true,
8490
+ "description": "Form-control name, for a native form submit.",
8491
+ "displayType": "undefined | string"
8492
+ },
8493
+ {
8494
+ "name": "valueLabel",
8495
+ "type": "undefined | false | true | ((value: number) => string)",
8496
+ "optional": true,
8497
+ "scalar": false,
8498
+ "description": "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.",
8499
+ "displayType": "undefined | false | true | ((value: number) => string)"
8500
+ }
8501
+ ],
8502
+ "events": [
8503
+ {
8504
+ "name": "kai-change",
8505
+ "detail": "{ value: number }",
8506
+ "description": "The value was committed: pointer released, or a key press finished.",
8507
+ "displayDetail": "{ value: number }"
8508
+ },
8509
+ {
8510
+ "name": "kai-input",
8511
+ "detail": "{ value: number }",
8512
+ "description": "The thumb moved. Fires per step during a drag or a key press.",
8513
+ "displayDetail": "{ value: number }"
8514
+ }
8515
+ ],
8516
+ "methods": [
8517
+ {
8518
+ "name": "focus",
8519
+ "params": "options?: FocusOptions",
8520
+ "returns": "void",
8521
+ "description": "Focus the inner range input (the host element can't reach it)."
8522
+ }
8523
+ ],
8524
+ "composedFrom": [
8525
+ {
8526
+ "name": "Slider",
8527
+ "group": "UI",
8528
+ "storyId": "solid-advanced-primitives-slider--docs"
8529
+ }
8530
+ ],
8531
+ "tokens": []
8532
+ },
7335
8533
  {
7336
8534
  "tag": "kai-source",
7337
8535
  "className": "KaiSourceElement",
@@ -8298,7 +9496,7 @@
8298
9496
  "type": "undefined | { id: string; message: string; variant?: undefined | \"neutral\" | \"success\" | \"warning\" | \"error\" | \"info\"; appearance?: undefined | \"pill\" | \"card\"; inverse?: undefined | false | true; description?: undefined | string; action?: undefined | { label: string; onAction: () => void | false }; duration?: undefined | number; dismissible?: undefined | false | true; target?: undefined | HTMLElement }[]",
8299
9497
  "optional": true,
8300
9498
  "scalar": false,
8301
- "description": "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.",
9499
+ "description": "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.",
8302
9500
  "typeName": "ToastItem[]",
8303
9501
  "typeShape": "{ id: string; message: string; variant?: undefined | \"neutral\" | \"success\" | \"warning\" | \"error\" | \"info\"; appearance?: undefined | \"pill\" | \"card\"; inverse?: undefined | false | true; description?: undefined | string; action?: undefined | { label: string; onAction: () => void | false }; duration?: undefined | number; dismissible?: undefined | false | true; target?: undefined | HTMLElement }[]",
8304
9502
  "default": "[]",
@@ -8610,11 +9808,11 @@
8610
9808
  },
8611
9809
  {
8612
9810
  "name": "transcribe",
8613
- "type": "undefined | (audio: Blob) => Promise<string>",
9811
+ "type": "undefined | ((audio: Blob) => Promise<string>)",
8614
9812
  "optional": true,
8615
9813
  "scalar": false,
8616
9814
  "description": "Transcriber the host supplies: records audio, returns the text. This is a **function-valued property** (`el.transcribe = async blob => '...'`) because a value-returning callback can't be modelled as a fire-and-forget event.",
8617
- "displayType": "undefined | (audio: Blob) => Promise<string>"
9815
+ "displayType": "undefined | ((audio: Blob) => Promise<string>)"
8618
9816
  },
8619
9817
  {
8620
9818
  "name": "disabled",
@@ -8667,6 +9865,12 @@
8667
9865
  "detail": "{ text: string }",
8668
9866
  "description": "Final transcript: the `transcribe` property resolved, OR native `SpeechRecognition` produced final text (no `transcribe` set).",
8669
9867
  "displayDetail": "{ text: string }"
9868
+ },
9869
+ {
9870
+ "name": "kai-voice-error",
9871
+ "detail": "{ source: \"recognition\"; error: string; message: string }",
9872
+ "description": "A voice session failed, so no failure is ever silent. `detail.source` names the failing side (`recognition` on `<kai-voice-input>`, `synthesis` on `<kai-voice-output>`), `detail.error` carries the platform error code, the thrown exception's name, or `no-result` when recognition ended with no error and no text (the user said nothing), and `detail.message` is human-readable. Deliberate cancellation does not fire.",
9873
+ "displayDetail": "{ source: \"recognition\"; error: string; message: string }"
8670
9874
  }
8671
9875
  ],
8672
9876
  "methods": [
@@ -8727,11 +9931,11 @@
8727
9931
  },
8728
9932
  {
8729
9933
  "name": "synthesize",
8730
- "type": "undefined | (text: string) => Promise<Blob>",
9934
+ "type": "undefined | ((text: string) => Promise<Blob>)",
8731
9935
  "optional": true,
8732
9936
  "scalar": false,
8733
9937
  "description": "TTS model seam the host supplies: given text, returns an audio `Blob` to play. This is a **function-valued property** (`el.synthesize = async text => blob`); when set, the native `speechSynthesis` path is bypassed. Mirrors `<kai-voice-input>`'s `transcribe`. A value-returning callback can't be modelled as a fire-and-forget event, hence a property.",
8734
- "displayType": "undefined | (text: string) => Promise<Blob>"
9938
+ "displayType": "undefined | ((text: string) => Promise<Blob>)"
8735
9939
  },
8736
9940
  {
8737
9941
  "name": "disabled",
@@ -8747,7 +9951,7 @@
8747
9951
  {
8748
9952
  "name": "kai-speaking-change",
8749
9953
  "detail": "{ speaking: false | true }",
8750
- "description": "Playback started or stopped. Drive your own UI in sync. Fires on real transitions only (manual click and programmatic speak()/stop()), never on mount.",
9954
+ "description": "Playback started or stopped. Drive your own UI in sync. `speaking: true` fires when audio actually starts (utterance.onstart natively; audio playback beginning on the `synthesize` path), not when speak() is called; earlier releases fired it optimistically inside speak() itself. Fires on real transitions only (manual click and programmatic speak()/stop()), never on mount.",
8751
9955
  "displayDetail": "{ speaking: false | true }"
8752
9956
  },
8753
9957
  {
@@ -8755,6 +9959,12 @@
8755
9959
  "detail": "{ blob: Blob }",
8756
9960
  "description": "The model path (`synthesize`) resolved audio: the raw `Blob` before playback.",
8757
9961
  "displayDetail": "{ blob: Blob }"
9962
+ },
9963
+ {
9964
+ "name": "kai-voice-error",
9965
+ "detail": "{ source: \"synthesis\"; error: string; message: string }",
9966
+ "description": "A voice session failed, so no failure is ever silent. `detail.source` names the failing side (`recognition` on `<kai-voice-input>`, `synthesis` on `<kai-voice-output>`), `detail.error` carries the platform error code, the thrown exception's name, or `no-result` when recognition ended with no error and no text (the user said nothing), and `detail.message` is human-readable. Deliberate cancellation does not fire.",
9967
+ "displayDetail": "{ source: \"synthesis\"; error: string; message: string }"
8758
9968
  }
8759
9969
  ],
8760
9970
  "methods": [
@@ -8815,252 +10025,51 @@
8815
10025
  "displayType": "\"light\" | \"dark\" | \"auto\""
8816
10026
  },
8817
10027
  {
8818
- "name": "groups",
8819
- "type": "undefined | { id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string }[]",
10028
+ "name": "startCollapsed",
10029
+ "type": "undefined | false | true",
8820
10030
  "optional": true,
8821
- "scalar": false,
8822
- "description": "The sidebar's section headers, rendered in array order. A group carries no conversations of its own; it is matched against `conversations` by id, so the two props are complementary rather than alternatives. Omit for an ungrouped sidebar. Set as a JS property.",
8823
- "typeName": "ConversationGroup[]",
8824
- "typeShape": "{ id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string }[]",
8825
- "default": "[]",
8826
- "typeImport": "ConversationGroup",
8827
- "displayType": "undefined | { id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string }[]"
10031
+ "scalar": true,
10032
+ "description": "Controlled collapsed state of the start aside. Set this as a JS property (`el.startCollapsed = true`) to drive the aside from your app, updating it in response to the `kai-aside-toggle` event. Omit for uncontrolled (the element manages it).",
10033
+ "displayType": "undefined | false | true"
8828
10034
  },
8829
10035
  {
8830
- "name": "conversations",
8831
- "type": "undefined | { id: string; title: string; groupId?: undefined | string; scope: { type: \"document\" | \"collection\"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | \"transcript\" | \"markdown\"; dateRange?: undefined | { from: string; to: string } } }; messageCount: number; lastMessageAt: string; updatedAt: string; trailing?: undefined | string }[]",
10036
+ "name": "defaultStartCollapsed",
10037
+ "type": "undefined | false | true",
8832
10038
  "optional": true,
8833
- "scalar": false,
8834
- "description": "Every conversation in the sidebar, flat. Each one is filed under the group whose `id` equals its `groupId`; one with no `groupId`, or with a `groupId` matching no entry in `groups`, falls into a trailing ungrouped section (headerless when `compact`), so nothing you pass in is ever dropped. There is no recency bucketing. Set as a JS property. Omit for an empty sidebar, or when `no-conversations` replaces the built-in list with your own `sidebar-header` content.",
8835
- "typeName": "ConversationSummary[]",
8836
- "typeShape": "{ id: string; title: string; groupId?: undefined | string; scope: { type: \"document\" | \"collection\"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | \"transcript\" | \"markdown\"; dateRange?: undefined | { from: string; to: string } } }; messageCount: number; lastMessageAt: string; updatedAt: string; trailing?: undefined | string }[]",
8837
- "default": "[]",
8838
- "typeImport": "ConversationSummary",
8839
- "displayType": "undefined | { id: string; title: string; groupId?: undefined | string; scope: { type: \"document\" | \"collection\"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | \"transcript\" | \"markdown\"; dateRange?: undefined | { from: string; to: string } } }; messageCount: number; lastMessageAt: string; updatedAt: string; trailing?: undefined | string }[]"
10039
+ "scalar": true,
10040
+ "description": "Initial collapsed state of the start aside when uncontrolled (default false). Use the `default-start-collapsed` attribute to start collapsed in plain HTML.",
10041
+ "displayType": "undefined | false | true"
8840
10042
  },
8841
10043
  {
8842
- "name": "activeId",
8843
- "type": "undefined | string",
10044
+ "name": "endCollapsed",
10045
+ "type": "undefined | false | true",
8844
10046
  "optional": true,
8845
10047
  "scalar": true,
8846
- "description": "Id of the open conversation, highlighted in the sidebar.",
8847
- "displayType": "undefined | string"
8848
- },
8849
- {
8850
- "name": "messages",
8851
- "type": "undefined | { id: string; role: \"user\" | \"assistant\"; parts: ({ type: \"text\"; text: string; raw?: undefined | { source: string; payload: unknown } } | { type: \"reasoning\"; text: string; label?: undefined | string; index?: undefined | number; streamId?: undefined | string; signature?: undefined | string; raw?: undefined | { source: string; payload: unknown } } | { type: \"tool\"; tool: { type: string; kind?: undefined | \"command\" | \"file-change\" | \"search\" | \"fetch\" | \"mcp\" | \"image\" | \"generic\"; state: \"input-streaming\" | \"input-available\" | \"output-available\" | \"output-error\"; input?: undefined | Record<string, unknown>; rawInput?: undefined | string; output?: undefined | Record<string, unknown>; toolCallId?: undefined | string; errorText?: undefined | string; raw?: undefined | { source: string; payload: unknown } }; raw?: undefined | { source: string; payload: unknown } } | { type: \"card\"; envelope: { type: string; id: string; data: unknown; title?: undefined | string; resolution?: undefined | { kind: \"action\"; action: string; payload?: unknown; at?: undefined | string } | { kind: \"submit\"; data: unknown; at?: undefined | string } | { kind: \"dismissed\"; at?: undefined | string } | { kind: \"expired\"; reason?: undefined | string; at?: undefined | string } }; raw?: undefined | { source: string; payload: unknown } } | { type: \"source\"; source: { id?: undefined | string; url?: undefined | string; title?: undefined | string; snippet?: undefined | string; index?: undefined | number }; raw?: undefined | { source: string; payload: unknown } } | { type: \"file\"; attachment: { id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }; raw?: undefined | { source: string; payload: unknown } })[]; actions?: undefined | (\"copy\" | \"like\" | \"dislike\" | \"regenerate\" | \"edit\" | { id: string; label: string; icon?: undefined | string; tooltip?: undefined | string })[]; avatar?: undefined | { src?: undefined | string; fallback?: undefined | string; alt?: undefined | string }; feedback?: undefined | \"like\" | \"dislike\" }[]",
8852
- "optional": true,
8853
- "scalar": false,
8854
- "description": "The active conversation's message thread, newest last. Set as a JS property (`el.messages = [...]`); a NEW array reference per streaming chunk re-renders (mutating in place does not). Omit for an empty thread.",
8855
- "typeName": "ChatMessage[]",
8856
- "typeShape": "{ id: string; role: \"user\" | \"assistant\"; parts: ({ type: \"text\"; text: string; raw?: undefined | { source: string; payload: unknown } } | { type: \"reasoning\"; text: string; label?: undefined | string; index?: undefined | number; streamId?: undefined | string; signature?: undefined | string; raw?: undefined | { source: string; payload: unknown } } | { type: \"tool\"; tool: { type: string; kind?: undefined | \"command\" | \"file-change\" | \"search\" | \"fetch\" | \"mcp\" | \"image\" | \"generic\"; state: \"input-streaming\" | \"input-available\" | \"output-available\" | \"output-error\"; input?: undefined | Record<string, unknown>; rawInput?: undefined | string; output?: undefined | Record<string, unknown>; toolCallId?: undefined | string; errorText?: undefined | string; raw?: undefined | { source: string; payload: unknown } }; raw?: undefined | { source: string; payload: unknown } } | { type: \"card\"; envelope: { type: string; id: string; data: unknown; title?: undefined | string; resolution?: undefined | { kind: \"action\"; action: string; payload?: unknown; at?: undefined | string } | { kind: \"submit\"; data: unknown; at?: undefined | string } | { kind: \"dismissed\"; at?: undefined | string } | { kind: \"expired\"; reason?: undefined | string; at?: undefined | string } }; raw?: undefined | { source: string; payload: unknown } } | { type: \"source\"; source: { id?: undefined | string; url?: undefined | string; title?: undefined | string; snippet?: undefined | string; index?: undefined | number }; raw?: undefined | { source: string; payload: unknown } } | { type: \"file\"; attachment: { id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }; raw?: undefined | { source: string; payload: unknown } })[]; actions?: undefined | (\"copy\" | \"like\" | \"dislike\" | \"regenerate\" | \"edit\" | { id: string; label: string; icon?: undefined | string; tooltip?: undefined | string })[]; avatar?: undefined | { src?: undefined | string; fallback?: undefined | string; alt?: undefined | string }; feedback?: undefined | \"like\" | \"dislike\" }[]",
8857
- "default": "[]",
8858
- "typeImport": "ChatMessage",
8859
- "displayType": "undefined | { id: string; role: \"user\" | \"assistant\"; parts: ({ type: \"text\"; text: string; raw?: undefined | { source: string; payload: unknown } } | { type: \"reasoning\"; text: string; label?: undefined | string; index?: undefined | number; streamId?: undefined | string; signature?: undefined | string; raw?: undefined | { source: string; payload: unknown } } | { type: \"tool\"; tool: { type: string; kind?: undefined | \"command\" | \"file-change\" | \"search\" | \"fetch\" | \"mcp\" | \"image\" | \"generic\"; state: \"input-streaming\" | \"input-available\" | \"output-available\" | \"output-error\"; input?: undefined | Record<string, unknown>; rawInput?: undefined | string; output?: undefined | Record<string, unknown>; toolCallId?: undefined | string; errorText?: undefined | string; raw?: undefined | { source: string; payload: unknown } }; raw?: undefined | { source: string; payload: unknown } } | { type: \"card\"; envelope: { type: string; id: string; data: unknown; title?: undefined | string; resolution?: undefined | { kind: \"action\"; action: string; payload?: unknown; at?: undefined | string } | { kind: \"submit\"; data: unknown; at?: undefined | string } | { kind: \"dismissed\"; at?: undefined | string } | { kind: \"expired\"; reason?: undefined | string; at?: undefined | string } }; raw?: undefined | { source: string; payload: unknown } } | { type: \"source\"; source: { id?: undefined | string; url?: undefined | string; title?: undefined | string; snippet?: undefined | string; index?: undefined | number }; raw?: undefined | { source: string; payload: unknown } } | { type: \"file\"; attachment: { id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }; raw?: undefined | { source: string; payload: unknown } })[]; actions?: undefined | (\"copy\" | \"like\" | \"dislike\" | \"regenerate\" | \"edit\" | { id: string; label: string; icon?: undefined | string; tooltip?: undefined | string })[]; avatar?: undefined | { src?: undefined | string; fallback?: undefined | string; alt?: undefined | string }; feedback?: undefined | \"like\" | \"dislike\" }[]"
8860
- },
8861
- {
8862
- "name": "value",
8863
- "type": "undefined | string",
8864
- "optional": true,
8865
- "scalar": true,
8866
- "description": "",
8867
- "displayType": "undefined | string"
8868
- },
8869
- {
8870
- "name": "placeholder",
8871
- "type": "undefined | string",
8872
- "optional": true,
8873
- "scalar": true,
8874
- "description": "",
8875
- "default": "'Send a message...'",
8876
- "displayType": "undefined | string"
8877
- },
8878
- {
8879
- "name": "loading",
8880
- "type": "undefined | false | true",
8881
- "optional": true,
8882
- "scalar": true,
8883
- "description": "",
8884
- "default": "false",
10048
+ "description": "Controlled collapsed state of the end aside. Set this as a JS property (`el.endCollapsed = true`) to drive the aside from your app, updating it in response to the `kai-aside-toggle` event. Omit for uncontrolled (the element manages it).",
8885
10049
  "displayType": "undefined | false | true"
8886
10050
  },
8887
10051
  {
8888
- "name": "suggestions",
8889
- "type": "undefined | string[]",
8890
- "optional": true,
8891
- "scalar": false,
8892
- "description": "",
8893
- "displayType": "undefined | string[]"
8894
- },
8895
- {
8896
- "name": "suggestionMode",
8897
- "type": "undefined | \"submit\" | \"fill\"",
8898
- "optional": true,
8899
- "scalar": true,
8900
- "description": "",
8901
- "default": "'submit'",
8902
- "displayType": "undefined | \"submit\" | \"fill\""
8903
- },
8904
- {
8905
- "name": "proseSize",
8906
- "type": "undefined | \"xs\" | \"sm\" | \"base\" | \"lg\"",
8907
- "optional": true,
8908
- "scalar": true,
8909
- "description": "",
8910
- "default": "'sm'",
8911
- "displayType": "undefined | \"xs\" | \"sm\" | \"base\" | \"lg\""
8912
- },
8913
- {
8914
- "name": "codeTheme",
8915
- "type": "undefined | string",
8916
- "optional": true,
8917
- "scalar": true,
8918
- "description": "",
8919
- "default": "'github-dark-dimmed'",
8920
- "displayType": "undefined | string"
8921
- },
8922
- {
8923
- "name": "codeHighlight",
10052
+ "name": "defaultEndCollapsed",
8924
10053
  "type": "undefined | false | true",
8925
10054
  "optional": true,
8926
10055
  "scalar": true,
8927
- "description": "",
8928
- "default": "true",
10056
+ "description": "Initial collapsed state of the end aside when uncontrolled (default false). Use the `default-end-collapsed` attribute to start collapsed in plain HTML.",
8929
10057
  "displayType": "undefined | false | true"
8930
10058
  },
8931
10059
  {
8932
- "name": "chatTitle",
8933
- "type": "undefined | string",
8934
- "optional": true,
8935
- "scalar": true,
8936
- "description": "",
8937
- "displayType": "undefined | string"
8938
- },
8939
- {
8940
- "name": "models",
8941
- "type": "undefined | { id: string; name: string; provider?: undefined | string; description?: undefined | string; group?: undefined | string }[]",
8942
- "optional": true,
8943
- "scalar": false,
8944
- "description": "",
8945
- "typeName": "ModelOption[]",
8946
- "typeShape": "{ id: string; name: string; provider?: undefined | string; description?: undefined | string; group?: undefined | string }[]",
8947
- "typeImport": "ModelOption",
8948
- "displayType": "undefined | { id: string; name: string; provider?: undefined | string; description?: undefined | string; group?: undefined | string }[]"
8949
- },
8950
- {
8951
- "name": "currentModel",
8952
- "type": "undefined | string",
8953
- "optional": true,
8954
- "scalar": true,
8955
- "description": "",
8956
- "displayType": "undefined | string"
8957
- },
8958
- {
8959
- "name": "context",
8960
- "type": "undefined | { usedTokens: number; maxTokens: number; inputTokens?: undefined | number; outputTokens?: undefined | number; estimatedCost?: undefined | number }",
8961
- "optional": true,
8962
- "scalar": false,
8963
- "description": "",
8964
- "typeName": "ChatThreadContextUsage",
8965
- "typeShape": "{ usedTokens: number; maxTokens: number; inputTokens?: undefined | number; outputTokens?: undefined | number; estimatedCost?: undefined | number }",
8966
- "typeImport": "ChatThreadContextUsage",
8967
- "displayType": "ContextData | undefined"
8968
- },
8969
- {
8970
- "name": "scrollButton",
8971
- "type": "undefined | false | true",
8972
- "optional": true,
8973
- "scalar": true,
8974
- "description": "",
8975
- "default": "true",
8976
- "displayType": "undefined | false | true"
8977
- },
8978
- {
8979
- "name": "search",
8980
- "type": "undefined | false | true",
8981
- "optional": true,
8982
- "scalar": true,
8983
- "description": "",
8984
- "default": "false",
8985
- "displayType": "undefined | false | true"
8986
- },
8987
- {
8988
- "name": "voice",
8989
- "type": "undefined | false | true",
8990
- "optional": true,
8991
- "scalar": true,
8992
- "description": "",
8993
- "default": "false",
8994
- "displayType": "undefined | false | true"
8995
- },
8996
- {
8997
- "name": "triggers",
8998
- "type": "undefined | { char: string; kind: string; items?: undefined | { id: string; label: string; icon?: undefined | string; description?: undefined | string; group?: undefined | string; kind?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown> }[] }[]",
8999
- "optional": true,
9000
- "scalar": false,
9001
- "description": "Rich entity triggers (`/` skills, `@` agents/plugins) forwarded to the input.",
9002
- "typeName": "TriggerDef[]",
9003
- "typeShape": "{ char: string; kind: string; items?: undefined | { id: string; label: string; icon?: undefined | string; description?: undefined | string; group?: undefined | string; kind?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown> }[] }[]",
9004
- "typeImport": "TriggerDef",
9005
- "displayType": "undefined | { char: string; kind: string; items?: undefined | { id: string; label: string; icon?: undefined | string; description?: undefined | string; group?: undefined | string; kind?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown> }[] }[]"
9006
- },
9007
- {
9008
- "name": "kindIcons",
9009
- "type": "undefined | Record<string, string>",
9010
- "optional": true,
9011
- "scalar": false,
9012
- "description": "Default icon per entity kind (kind → image src) forwarded to the input.",
9013
- "displayType": "undefined | Record<string, string>"
9014
- },
9015
- {
9016
- "name": "sidebarWidth",
9017
- "type": "undefined | number",
9018
- "optional": true,
9019
- "scalar": true,
9020
- "description": "Sidebar default width as a percent of the workspace (default 26).",
9021
- "default": "26",
9022
- "displayType": "undefined | number"
9023
- },
9024
- {
9025
- "name": "sidebarMinWidth",
9026
- "type": "undefined | number",
9027
- "optional": true,
9028
- "scalar": true,
9029
- "description": "Sidebar min width in px (default 240).",
9030
- "default": "240",
9031
- "displayType": "undefined | number"
9032
- },
9033
- {
9034
- "name": "sidebarMaxWidth",
10060
+ "name": "collapseBelow",
9035
10061
  "type": "undefined | number",
9036
10062
  "optional": true,
9037
10063
  "scalar": true,
9038
- "description": "Sidebar max width in px (default 420).",
9039
- "default": "420",
10064
+ "description": "Auto-collapse both asides when the shell's own width drops below this many px, and re-expand when it grows back above. Applies to uncontrolled asides only (it never fights an app-driven collapsed prop); omit to disable. Fires `kai-aside-toggle`. Attribute: `collapse-below`.",
9040
10065
  "displayType": "undefined | number"
9041
10066
  },
9042
10067
  {
9043
- "name": "sidebarCollapsed",
9044
- "type": "undefined | false | true",
9045
- "optional": true,
9046
- "scalar": true,
9047
- "description": "Controlled collapsed state. Set this as a JS property (`el.sidebarCollapsed = true`) to drive the sidebar from your app, updating it in response to the `kai-sidebar-toggle` event. Omit for uncontrolled (the element manages it).",
9048
- "displayType": "undefined | false | true"
9049
- },
9050
- {
9051
- "name": "defaultSidebarCollapsed",
9052
- "type": "undefined | false | true",
9053
- "optional": true,
9054
- "scalar": true,
9055
- "description": "Initial collapsed state when uncontrolled (default false). Use the `default-sidebar-collapsed` attribute to start collapsed in plain HTML.",
9056
- "displayType": "undefined | false | true"
9057
- },
9058
- {
9059
- "name": "collapseBelow",
10068
+ "name": "drawerBelow",
9060
10069
  "type": "undefined | number",
9061
10070
  "optional": true,
9062
10071
  "scalar": true,
9063
- "description": "Auto-collapse the rail when the workspace's own width drops below this many px, and re-expand when it grows back above. Uncontrolled only (it never fights an app-driven `sidebarCollapsed`); omit to disable. Fires `kai-sidebar-toggle`. Attribute: `collapse-below`.",
10072
+ "description": "Below this shell width in px, an expanded aside renders as an overlay drawer over the main region instead of a column beside it. Escape inside the drawer closes it and returns focus to the element focused before it opened. Omit to disable. Attribute: `drawer-below`.",
9064
10073
  "displayType": "undefined | number"
9065
10074
  },
9066
10075
  {
@@ -9068,200 +10077,114 @@
9068
10077
  "type": "undefined | false | true",
9069
10078
  "optional": true,
9070
10079
  "scalar": true,
9071
- "description": "Render Recents as dense single-line rows (a leading dot + title, no count).",
10080
+ "description": "Density hint. Reflected as a `data-compact` hook on the root (and as the `compact` attribute on the element) for your CSS and slotted content; the shell itself keeps no other opinion about density.",
9072
10081
  "displayType": "undefined | false | true"
9073
- },
9074
- {
9075
- "name": "noConversations",
9076
- "type": "undefined | false | true",
9077
- "optional": true,
9078
- "scalar": true,
9079
- "description": "Suppress the built-in ConversationList so the `sidebar-header` slot owns the whole rail flex region (for apps that supply their own rail nav). Default false. Attribute: `no-conversations`.",
9080
- "displayType": "undefined | false | true"
9081
- },
9082
- {
9083
- "name": "cardTypes",
9084
- "type": "undefined | Record<string, string>",
9085
- "optional": true,
9086
- "scalar": false,
9087
- "description": "Optional card type -> custom-element tag overrides/additions for `card` parts (merged over the built-ins). Property: `el.cardTypes`. Typed as a plain string map (not the `CardTagMap` alias) so the generated React wrapper inlines it instead of emitting an unresolved named type.",
9088
- "displayType": "undefined | Record<string, string>"
9089
- },
9090
- {
9091
- "name": "cardSchemas",
9092
- "type": "undefined | Record<string, object>",
9093
- "optional": true,
9094
- "scalar": false,
9095
- "description": "JSON Schemas for the card types this app renders, keyed by envelope type. The companion of `cardTypes`, 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.cardSchemas = { '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. 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.",
9096
- "displayType": "undefined | Record<string, object>"
9097
10082
  }
9098
10083
  ],
9099
10084
  "events": [
9100
10085
  {
9101
- "name": "kai-conversation-select",
9102
- "detail": "{ id: string }",
9103
- "description": "A conversation was selected in the sidebar.",
9104
- "displayDetail": "{ id: string }"
9105
- },
9106
- {
9107
- "name": "kai-message-action",
9108
- "detail": "{ messageId: string; action: string; state?: undefined | \"on\" | \"off\" }",
9109
- "description": "An action button on a message was clicked. `state` is present only for the toggleable feedback votes: `'on'` when a like/dislike is set, `'off'` when re-tapped to clear.",
9110
- "displayDetail": "{ messageId: string; action: string; state?: undefined | \"on\" | \"off\" }"
9111
- },
9112
- {
9113
- "name": "kai-model-change",
9114
- "detail": "{ modelId: string }",
9115
- "description": "The header model switcher changed.",
9116
- "displayDetail": "{ modelId: string }"
9117
- },
9118
- {
9119
- "name": "kai-new-chat",
9120
- "detail": "Record<string, never>",
9121
- "description": "The \"New chat\" button was clicked.",
9122
- "displayDetail": "Record<string, never>"
9123
- },
9124
- {
9125
- "name": "kai-search",
9126
- "detail": "Record<string, never>",
9127
- "description": "The Search button was clicked.",
9128
- "displayDetail": "Record<string, never>"
9129
- },
9130
- {
9131
- "name": "kai-sidebar-toggle",
9132
- "detail": "{ collapsed: false | true }",
9133
- "description": "The sidebar was collapsed or expanded.",
9134
- "displayDetail": "{ collapsed: false | true }"
9135
- },
9136
- {
9137
- "name": "kai-submit",
9138
- "detail": "{ value: string; attachments: { id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[] }",
9139
- "description": "User submitted a message.",
9140
- "displayDetail": "{ value: string; attachments: AttachmentData[] }"
9141
- },
9142
- {
9143
- "name": "kai-suggestion-click",
9144
- "detail": "{ value: string }",
9145
- "description": "A suggestion chip was clicked (only in `suggestion-mode=\"fill\"`).",
9146
- "displayDetail": "{ value: string }"
9147
- },
9148
- {
9149
- "name": "kai-value-change",
9150
- "detail": "{ value: string }",
9151
- "description": "Fired on every input change.",
9152
- "displayDetail": "{ value: string }"
10086
+ "name": "kai-aside-resize",
10087
+ "detail": "{ side: \"start\" | \"end\"; width: number }",
10088
+ "description": "The aside was resized (fires per drag step, keyboard nudge, or a handle double-click reset), width in px.",
10089
+ "displayDetail": "{ side: \"start\" | \"end\"; width: number }"
9153
10090
  },
9154
10091
  {
9155
- "name": "kai-voice",
9156
- "detail": "Record<string, never>",
9157
- "description": "The Mic / voice button was clicked.",
9158
- "displayDetail": "Record<string, never>"
10092
+ "name": "kai-aside-toggle",
10093
+ "detail": "{ side: \"start\" | \"end\"; collapsed: false | true }",
10094
+ "description": "An aside collapsed or expanded (a method, the breakpoint, the drawer's Escape).",
10095
+ "displayDetail": "{ side: \"start\" | \"end\"; collapsed: false | true }"
9159
10096
  }
9160
10097
  ],
9161
10098
  "methods": [
9162
10099
  {
9163
- "name": "toggleSidebar",
9164
- "params": "",
10100
+ "name": "toggleAside",
10101
+ "params": "side: WorkspaceAsideSide",
9165
10102
  "returns": "void",
9166
- "description": "Collapse/expand the conversation sidebar and fire `kai-sidebar-toggle`."
10103
+ "description": "Collapse/expand one aside (fires `kai-aside-toggle`)."
9167
10104
  },
9168
10105
  {
9169
- "name": "collapseSidebar",
9170
- "params": "",
10106
+ "name": "collapseAside",
10107
+ "params": "side: WorkspaceAsideSide",
9171
10108
  "returns": "void",
9172
- "description": "Force the conversation sidebar collapsed (fires `kai-sidebar-toggle`)."
10109
+ "description": "Force one aside collapsed (fires `kai-aside-toggle`)."
9173
10110
  },
9174
10111
  {
9175
- "name": "expandSidebar",
9176
- "params": "",
9177
- "returns": "void",
9178
- "description": "Force the conversation sidebar expanded (fires `kai-sidebar-toggle`)."
9179
- },
9180
- {
9181
- "name": "focus",
9182
- "params": "options?: FocusOptions",
9183
- "returns": "void",
9184
- "description": "Focus the thread's composer."
9185
- },
9186
- {
9187
- "name": "clear",
9188
- "params": "",
10112
+ "name": "expandAside",
10113
+ "params": "side: WorkspaceAsideSide",
9189
10114
  "returns": "void",
9190
- "description": "Clear the thread draft + staged attachments."
9191
- },
9192
- {
9193
- "name": "send",
9194
- "params": "",
9195
- "returns": "void",
9196
- "description": "Submit the current thread draft programmatically (fires `kai-submit`)."
9197
- },
9198
- {
9199
- "name": "scrollToBottom",
9200
- "params": "behavior?: ScrollBehavior",
9201
- "returns": "void",
9202
- "description": "Scroll the thread to the newest message."
10115
+ "description": "Force one aside expanded (fires `kai-aside-toggle`)."
9203
10116
  }
9204
10117
  ],
9205
10118
  "composedFrom": [
9206
10119
  {
9207
- "name": "ChatThread",
10120
+ "name": "WorkspaceShell",
9208
10121
  "group": "Components",
9209
- "storyId": "solid-advanced-elements-chatthread--docs"
10122
+ "storyId": "solid-advanced-elements-workspaceshell--docs"
10123
+ }
10124
+ ],
10125
+ "tokens": [],
10126
+ "slots": [
10127
+ {
10128
+ "name": "",
10129
+ "mode": "inject",
10130
+ "doc": "The main region content (same region as the `main` slot): your `<kai-chat>`, or any app view."
9210
10131
  },
9211
10132
  {
9212
- "name": "ConversationList",
9213
- "group": "Components",
9214
- "storyId": "solid-advanced-elements-conversationlist--docs"
10133
+ "name": "header",
10134
+ "mode": "inject",
10135
+ "part": true,
10136
+ "doc": "The top band across the full shell width (app bar, tabs, breadcrumbs)."
9215
10137
  },
9216
10138
  {
9217
- "name": "CollapsedRail",
9218
- "group": "Components",
9219
- "storyId": "solid-advanced-elements-collapsedrail--docs"
10139
+ "name": "start",
10140
+ "mode": "inject",
10141
+ "part": true,
10142
+ "doc": "The inline-start aside column (a conversation rail, a nav, a file tree). Resizable and collapsible."
9220
10143
  },
9221
10144
  {
9222
- "name": "ResizablePanelGroup",
9223
- "group": "UI",
9224
- "storyId": "solid-advanced-primitives-resizablepanelgroup--docs"
10145
+ "name": "main",
10146
+ "mode": "inject",
10147
+ "part": true,
10148
+ "doc": "The main region. Unnamed children project here too, via the default slot."
9225
10149
  },
9226
10150
  {
9227
- "name": "ResizablePanel",
9228
- "group": "UI",
9229
- "storyId": "solid-advanced-primitives-resizablepanel--docs"
10151
+ "name": "end",
10152
+ "mode": "inject",
10153
+ "part": true,
10154
+ "doc": "The inline-end aside column (inspector, notes, preview). Resizable and collapsible."
9230
10155
  },
9231
10156
  {
9232
- "name": "ResizableHandle",
9233
- "group": "UI",
9234
- "storyId": "solid-advanced-primitives-resizablehandle--docs"
10157
+ "name": "footer",
10158
+ "mode": "inject",
10159
+ "part": true,
10160
+ "doc": "The bottom band across the full shell width (status bar, disclaimers)."
9235
10161
  }
9236
10162
  ],
9237
- "tokens": [],
9238
- "slots": [
10163
+ "parts": [
9239
10164
  {
9240
- "name": "sidebar-header",
9241
- "mode": "inject",
9242
- "doc": "Top of the conversation rail (brand, a kai-tabs strip)."
10165
+ "name": "aside",
10166
+ "doc": "Both aside columns match this part (each also matches its own start/end part). Restyle the shared aside surface or border from outside; the --kai-workspace-start-* and --kai-workspace-end-* custom properties set the widths.",
10167
+ "recipe": "kai-workspace::part(aside) { background: var(--color-card) }"
9243
10168
  },
9244
10169
  {
9245
- "name": "sidebar-footer",
9246
- "mode": "inject",
9247
- "doc": "Bottom of the rail: an upgrade card, a Design trigger, a user-menu cluster."
10170
+ "name": "header",
10171
+ "doc": "The top band across the full shell width (app bar, tabs, breadcrumbs)."
9248
10172
  },
9249
10173
  {
9250
- "name": "main-header",
9251
- "mode": "inject",
9252
- "doc": "Top of the main region (a top-placed banner or a corner action)."
10174
+ "name": "start",
10175
+ "doc": "The inline-start aside column (a conversation rail, a nav, a file tree). Resizable and collapsible."
9253
10176
  },
9254
10177
  {
9255
10178
  "name": "main",
9256
- "mode": "replace",
9257
- "doc": "Replace the built-in chat thread with your own main view (a home or dashboard screen). Omit to keep the thread."
9258
- }
9259
- ],
9260
- "parts": [
10179
+ "doc": "The main region. Unnamed children project here too, via the default slot."
10180
+ },
9261
10181
  {
9262
- "name": "sidebar",
9263
- "doc": "The conversation rail. Carries a subtle, theme-aware default background (bg-surface); override its background, border, or width from outside. `sidebar-min-width` sets its min px width and `collapse-below` auto-collapses it under a width.",
9264
- "recipe": "kai-workspace::part(sidebar) { background: var(--color-card); border-right: 1px solid var(--color-border) }"
10182
+ "name": "end",
10183
+ "doc": "The inline-end aside column (inspector, notes, preview). Resizable and collapsible."
10184
+ },
10185
+ {
10186
+ "name": "footer",
10187
+ "doc": "The bottom band across the full shell width (status bar, disclaimers)."
9265
10188
  }
9266
10189
  ]
9267
10190
  }