@kitn.ai/ui 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (488) hide show
  1. package/README.md +25 -6
  2. package/bin/mcp.js +16 -3
  3. package/bin/route.js +23 -0
  4. package/bin/route.test.js +58 -0
  5. package/dist/{elements/chunks/Icon--Y8vsFal.js → Icon-DObhsRtm.js} +1 -1
  6. package/dist/action-icons-CcgNN2oT.js +1 -0
  7. package/dist/arrow-down-CjRU3JgV.js +1 -0
  8. package/dist/arrow-left-Bnpb1UEW.js +1 -0
  9. package/dist/artifact-Bwt7OgcR.js +1 -0
  10. package/dist/assets/dev-5XzXYR21.js +91 -0
  11. package/dist/attachments-Qr4kg-2b.js +1 -0
  12. package/dist/{elements/chunks/audio-visualizer-D7lB6mvR.js → audio-visualizer-DToYdfSc.js} +1 -1
  13. package/dist/badge-CdEu_jn2.js +1 -0
  14. package/dist/bash-InADTalH.js +1 -6
  15. package/dist/bell-DQAAOpDz.js +1 -0
  16. package/dist/{elements/chunks/button-flUbeufF.js → button-DkuOnGLy.js} +1 -1
  17. package/dist/card-renderer-Jx70m6_l.js +1 -0
  18. package/dist/card-routing-0YidER_3.js +1 -0
  19. package/dist/check-njkVdZu2.js +1 -0
  20. package/dist/checkbox-D7iRB3nL.js +1 -0
  21. package/dist/checkbox-group-B2_rpoPM.js +1 -0
  22. package/dist/chevron-down-B72s6PXR.js +1 -0
  23. package/dist/chevron-right-BatuHzUm.js +1 -0
  24. package/dist/choice-card-m0BYqqOK.js +1 -0
  25. package/dist/circle-check-B62pODB3.js +1 -0
  26. package/dist/circle-x-BPG0iPst.js +1 -0
  27. package/dist/circle-zx0ByzY9.js +1 -0
  28. package/dist/{elements/chunks/cn-CU7UAWzk.js → cn-DN5AWfiS.js} +1 -1
  29. package/dist/code-block-ClMLKb7C.js +1 -0
  30. package/dist/{elements/chunks/collapsible-BzbXpPzr.js → collapsible-B4DlWicL.js} +1 -1
  31. package/dist/components/attachment-types.d.ts +7 -0
  32. package/dist/components/audio-visualizer/fit-scale.d.ts +1 -1
  33. package/dist/components/card-renderer.d.ts +13 -0
  34. package/dist/components/card.d.ts +4 -0
  35. package/dist/components/chat-thread.d.ts +135 -2
  36. package/dist/components/conversation-item.d.ts +35 -7
  37. package/dist/components/conversation-list.d.ts +17 -5
  38. package/dist/components/conversation-panel.d.ts +29 -0
  39. package/dist/components/form-widgets.d.ts +67 -2
  40. package/dist/components/form.d.ts +48 -1
  41. package/dist/components/home-panel.d.ts +34 -0
  42. package/dist/components/message.d.ts +25 -3
  43. package/dist/components/reasoning.d.ts +6 -0
  44. package/dist/components/scroll-button.d.ts +11 -0
  45. package/dist/components/thread.d.ts +5 -0
  46. package/dist/components/tool-types.d.ts +9 -0
  47. package/dist/components/widget-tab-bar.d.ts +16 -0
  48. package/dist/composer-sQ0HcvyG.js +106 -0
  49. package/dist/confirm-card-rQWDQsnC.js +1 -0
  50. package/dist/construct-cli.es.js +1337 -0
  51. package/dist/{elements/chunks/context-VLIL3sJ-.js → context-0kg4ZX1J.js} +1 -1
  52. package/dist/controllable-CnGpMF6r.js +1 -0
  53. package/dist/conversation-item-BxwQLaFJ.js +1 -0
  54. package/dist/conversation-list-BCfGN1JU.js +1 -0
  55. package/dist/copy-n9u9rqpi.js +1 -0
  56. package/dist/core-AYMC6_lb.js +12 -5874
  57. package/dist/{create-tween-BFT6c-Y8.js → create-tween-C-q-JCM-.js} +1 -1
  58. package/dist/{create-tween-CJNlzoaO.js → create-tween-CRrJXxBd.js} +1 -1
  59. package/dist/{create-tween-CQED4T0g.js → create-tween-DZ3RRDHD.js} +1 -1
  60. package/dist/{elements/chunks/create-tween-c4Z8TDYz.js → create-tween-uPkArjIG.js} +2 -2
  61. package/dist/css-M7EaDHN_.js +1 -6
  62. package/dist/custom-elements.json +1433 -202
  63. package/dist/default-input-CaMrJkgH.js +1 -0
  64. package/dist/define-By-uL588.js +1 -0
  65. package/dist/define.d.ts +4 -0
  66. package/dist/define.js +510 -0
  67. package/dist/define.server.d.ts +5 -0
  68. package/dist/define.server.js +506 -0
  69. package/dist/{elements/chunks/disclosure-CcNbyLy0.js → disclosure-WUImBbDv.js} +1 -1
  70. package/dist/{elements/chunks/dropdown-BgWTthUx.js → dropdown-wZVeJOMd.js} +1 -1
  71. package/dist/elements/agent-card.js +1 -1
  72. package/dist/elements/artifact.js +1 -1
  73. package/dist/elements/attachments.js +1 -1
  74. package/dist/elements/audio-visualizer.js +1 -1
  75. package/dist/elements/autoloader.js +1 -1
  76. package/dist/elements/avatar.js +1 -1
  77. package/dist/elements/badge.js +1 -1
  78. package/dist/elements/button.js +1 -1
  79. package/dist/elements/card.js +1 -1
  80. package/dist/elements/cards.js +1 -1
  81. package/dist/elements/chain-of-thought.js +1 -1
  82. package/dist/elements/chat-scope-picker.js +1 -1
  83. package/dist/elements/chat-workspace.js +1 -1
  84. package/dist/elements/chat.js +1 -1
  85. package/dist/elements/checkbox-group.d.ts +1 -0
  86. package/dist/elements/checkbox-group.js +1 -0
  87. package/dist/elements/checkbox.d.ts +1 -0
  88. package/dist/elements/checkbox.js +1 -0
  89. package/dist/elements/checkpoint.js +1 -1
  90. package/dist/elements/choice.js +1 -1
  91. package/dist/elements/coachmark.js +1 -1
  92. package/dist/elements/code-block.js +1 -1
  93. package/dist/elements/command.js +1 -1
  94. package/dist/elements/compare.js +1 -1
  95. package/dist/elements/composer.js +1 -1
  96. package/dist/elements/confirm-card.js +1 -1
  97. package/dist/elements/context-meter.js +1 -1
  98. package/dist/elements/conversation-item.js +1 -1
  99. package/dist/elements/conversation-list.js +1 -1
  100. package/dist/elements/define-entry.d.ts +12 -0
  101. package/dist/elements/dialog.js +1 -1
  102. package/dist/elements/dock.js +102 -8
  103. package/dist/elements/dropdown.js +1 -1
  104. package/dist/elements/editable-label.js +1 -1
  105. package/dist/elements/element-data-types.d.ts +37 -0
  106. package/dist/elements/embed.js +1 -1
  107. package/dist/elements/empty.js +1 -1
  108. package/dist/elements/feedback-bar.js +1 -1
  109. package/dist/elements/file-tree.js +1 -1
  110. package/dist/elements/file-upload.js +1 -1
  111. package/dist/elements/form.js +1 -1
  112. package/dist/elements/hover-card.js +1 -1
  113. package/dist/elements/icon.js +1 -1
  114. package/dist/elements/image.js +1 -1
  115. package/dist/elements/input.js +1 -1
  116. package/dist/elements/kbd.js +1 -1
  117. package/dist/elements/link-preview.js +1 -1
  118. package/dist/elements/loader.js +1 -1
  119. package/dist/elements/markdown.js +1 -1
  120. package/dist/elements/menu.js +1 -1
  121. package/dist/elements/message-skills.js +1 -1
  122. package/dist/elements/message.js +1 -1
  123. package/dist/elements/model-switcher.js +1 -1
  124. package/dist/elements/nav.js +1 -1
  125. package/dist/elements/notice.js +1 -1
  126. package/dist/elements/pane-grid.d.ts +1 -0
  127. package/dist/elements/pane-grid.js +1 -0
  128. package/dist/elements/pane-group.js +1 -1
  129. package/dist/elements/pane.js +1 -1
  130. package/dist/elements/popover.js +1 -1
  131. package/dist/elements/progress-bar.js +1 -1
  132. package/dist/elements/prompt-dock.js +1 -1
  133. package/dist/elements/prompt-input.js +1 -1
  134. package/dist/elements/prompt-suggestions.js +1 -1
  135. package/dist/elements/radio-group.d.ts +1 -0
  136. package/dist/elements/radio-group.js +1 -0
  137. package/dist/elements/reasoning.js +1 -1
  138. package/dist/elements/remote.js +1 -1
  139. package/dist/elements/resizable.js +1 -1
  140. package/dist/elements/response-stream.js +2 -2
  141. package/dist/elements/screen.js +1 -1
  142. package/dist/elements/scroll-area.js +1 -1
  143. package/dist/elements/scroll-button.js +1 -1
  144. package/dist/elements/search.js +1 -1
  145. package/dist/elements/segmented.js +1 -1
  146. package/dist/elements/select.d.ts +1 -0
  147. package/dist/elements/select.js +1 -0
  148. package/dist/elements/separator.js +1 -1
  149. package/dist/elements/setting-item.js +1 -1
  150. package/dist/elements/settings-group.js +1 -1
  151. package/dist/elements/skeleton.js +1 -1
  152. package/dist/elements/slider.d.ts +1 -0
  153. package/dist/elements/slider.js +1 -0
  154. package/dist/elements/slots.d.ts +1 -1
  155. package/dist/elements/source.js +1 -1
  156. package/dist/elements/status.js +1 -1
  157. package/dist/elements/switch.js +1 -1
  158. package/dist/elements/tabs.js +1 -1
  159. package/dist/elements/tasks.js +1 -1
  160. package/dist/elements/text-shimmer.js +1 -1
  161. package/dist/elements/thinking-bar.js +1 -1
  162. package/dist/elements/thread.js +1 -1
  163. package/dist/elements/toast.js +1 -1
  164. package/dist/elements/tool.js +1 -1
  165. package/dist/elements/tooltip.js +1 -1
  166. package/dist/elements/voice-input.js +1 -1
  167. package/dist/elements/voice-output.js +1 -1
  168. package/dist/elements.d.ts +380 -26
  169. package/dist/{elements/chunks/ellipsis-7gU33mL2.js → ellipsis-CbOpJnU3.js} +1 -1
  170. package/dist/embed-CrfjkbUG.js +1 -0
  171. package/dist/engine-javascript-vq0WuIJl.js +14 -2516
  172. package/dist/{elements/chunks/external-link-CSOEsNlx.js → external-link-ByXAwBBQ.js} +1 -1
  173. package/dist/file-text-DMib2qwt.js +1 -0
  174. package/dist/{elements/chunks/file-tree-zvB2i7P9.js → file-tree-CJqM2aP7.js} +1 -1
  175. package/dist/folder-_BAb929C.js +1 -0
  176. package/dist/form-DSZgZQZk.js +1 -0
  177. package/dist/github-dark-dimmed-DUshB20C.js +1 -4
  178. package/dist/github-light-JYsPkUQd.js +1 -4
  179. package/dist/hover-card-BQbul9eq.js +1 -0
  180. package/dist/html-CPZ3oZQ7.js +1 -10
  181. package/dist/icon-CdcfRhYI.js +1 -0
  182. package/dist/{elements/chunks/index-BCRhi84a.js → index-xu_pdcPi.js} +1 -1
  183. package/dist/index.d.ts +4 -2
  184. package/dist/index.js +7474 -5857
  185. package/dist/index.server.js +5965 -4762
  186. package/dist/info-DsFjGuI_.js +1 -0
  187. package/dist/input-DKbmkMos.js +1 -0
  188. package/dist/javascript-C25yR2R2.js +1 -6
  189. package/dist/json-DxJze_jm.js +1 -6
  190. package/dist/kai.es.js +1 -1
  191. package/dist/kbd-PvdGhX4s.js +1 -0
  192. package/dist/{elements/chunks/link-preview-OQ9IEq0f.js → link-preview-DbM1866N.js} +1 -1
  193. package/dist/link-zF8PzWfF.js +1 -0
  194. package/dist/loader-BM4CEz4G.js +1 -0
  195. package/dist/{elements/chunks/markdown-DgBFaGAz.js → markdown-LMvmAyBk.js} +7 -7
  196. package/dist/mcp.es.js +1361 -81
  197. package/dist/message-BSsgvHvf.js +1 -0
  198. package/dist/message-BYZECyek.js +1 -0
  199. package/dist/message-circle-DruwObfX.js +1 -0
  200. package/dist/message-square-BG6q6mlm.js +1 -0
  201. package/dist/{elements/chunks/minimize-2-DPIUKTrT.js → minimize-2-BQRoBV1V.js} +1 -1
  202. package/dist/{elements/chunks/model-switcher-DsT8tFB0.js → model-switcher-CMpCOYcB.js} +1 -1
  203. package/dist/{elements/chunks/overlay-DuiwdXjm.js → overlay-Cb-MkyDa.js} +1 -1
  204. package/dist/panel-right-i8warFxT.js +1 -0
  205. package/dist/paperclip-ByY3UVO6.js +1 -0
  206. package/dist/play-BvKKq3fX.js +1 -0
  207. package/dist/primitives/card-data-types.d.ts +49 -0
  208. package/dist/primitives/card-routing.d.ts +1 -33
  209. package/dist/primitives/card-validate.d.ts +2 -2
  210. package/dist/primitives/chat-config.d.ts +29 -2
  211. package/dist/primitives/conversation-store.d.ts +54 -0
  212. package/dist/primitives/field-mask.d.ts +96 -0
  213. package/dist/primitives/field-semantics.d.ts +36 -0
  214. package/dist/primitives/input-mask.d.ts +46 -0
  215. package/dist/primitives/url-scheme-policy.d.ts +34 -0
  216. package/dist/primitives/use-resize-observer.d.ts +2 -2
  217. package/dist/progress-bar-jVAHvMUf.js +1 -0
  218. package/dist/prompt-suggestion-CD-qtNgC.js +1 -0
  219. package/dist/radio-BsoBMhkF.js +1 -0
  220. package/dist/react/index.d.ts +586 -19
  221. package/dist/react.js +223 -187
  222. package/dist/reasoning-4kBPtlTx.js +1 -0
  223. package/dist/register-impl-B1hLkrI8.js +424 -0
  224. package/dist/{elements/chunks/resizable-D181b4fM.js → resizable-uPmY9VY-.js} +1 -1
  225. package/dist/rotate-ccw-B2xn93py.js +1 -0
  226. package/dist/rotate-cw-CMVLoCyH.js +1 -0
  227. package/dist/schemas/form.schema.json +21 -1
  228. package/dist/schemas/tool-defs.d.ts +11 -1
  229. package/dist/schemas.js +81 -81
  230. package/dist/scroll-area-BqLUo8ZZ.js +1 -0
  231. package/dist/scroll-button-DslXiJyL.js +1 -0
  232. package/dist/select-2cLRtPGT.js +1 -0
  233. package/dist/{elements/chunks/separator-CeJHQqLW.js → separator-BWQtNJcM.js} +1 -1
  234. package/dist/{elements/chunks/settings-CqaHgJF9.js → settings-BBR63jLg.js} +1 -1
  235. package/dist/{elements/chunks/settings-group-CjqjLCOn.js → settings-group-B2ciy-Iw.js} +1 -1
  236. package/dist/{elements/chunks/skeleton-D8akBnKS.js → skeleton-CkHI-HgC.js} +1 -1
  237. package/dist/slider-DDR9U-i0.js +1 -0
  238. package/dist/{solid-BtdqNZI7.js → solid-BzCFdL25.js} +9771 -7594
  239. package/dist/{solid-CnavwBye.js → solid-DruVOXnf.js} +7893 -6183
  240. package/dist/solid.d.ts +16 -2
  241. package/dist/solid.js +256 -243
  242. package/dist/solid.server.js +256 -243
  243. package/dist/source-GEnFF528.js +1 -0
  244. package/dist/star-CilHq8GP.js +1 -0
  245. package/dist/state/index.d.ts +1 -1
  246. package/dist/state/mock.d.ts +32 -2
  247. package/dist/state.js +133 -108
  248. package/dist/store-Ciyk6eZG.js +1 -0
  249. package/dist/svelte--5p79yCD.js +1 -15
  250. package/dist/switch-KkeQIbuH.js +1 -0
  251. package/dist/tasks-card-BrN4bggJ.js +1 -0
  252. package/dist/text-shimmer-Dcj1MHuq.js +1 -0
  253. package/dist/textarea-Dpvbngbg.js +1 -0
  254. package/dist/theme.tokens.css +110 -13
  255. package/dist/{elements/chunks/thumbs-up-DX2Ijk3H.js → thumbs-up-CsT9Wzb9.js} +1 -1
  256. package/dist/toast-store-tgK6MuMv.js +1 -0
  257. package/dist/{elements/chunks/tool-DKQ2D1DP.js → tool-DzUjIBT8.js} +1 -1
  258. package/dist/{elements/chunks/tooltip-B0G99y8w.js → tooltip-Bkkg_4t0.js} +1 -1
  259. package/dist/trash-2-jBKxjGGQ.js +1 -0
  260. package/dist/{elements/chunks/triangle-alert-F9cyUEyy.js → triangle-alert-DlQ68ppf.js} +1 -1
  261. package/dist/tsx-B8rCNbgL.js +1 -6
  262. package/dist/types.d.ts +48 -3
  263. package/dist/typescript-RycA9KXf.js +1 -6
  264. package/dist/ui/checkbox-group.d.ts +83 -0
  265. package/dist/ui/checkbox.d.ts +40 -0
  266. package/dist/ui/dock.d.ts +51 -0
  267. package/dist/ui/icon.d.ts +3 -0
  268. package/dist/ui/input.d.ts +48 -2
  269. package/dist/ui/radio.d.ts +85 -0
  270. package/dist/ui/select.d.ts +71 -0
  271. package/dist/ui/slider.d.ts +65 -0
  272. package/dist/ui/switch.d.ts +9 -2
  273. package/dist/upload-TcAHXv9W.js +1 -0
  274. package/dist/url-scheme-policy-DR5DgvkM.js +1 -0
  275. package/dist/use-card-resolution-DaZqAdWf.js +1 -0
  276. package/dist/{elements/chunks/variant-aurora-qt6Zct8M.js → variant-aurora-BhLuYxJR.js} +1 -1
  277. package/dist/{variant-aurora-B8II3-I1.js → variant-aurora-CNmfHhcx.js} +2 -2
  278. package/dist/{variant-aurora-CMNWOSJR.js → variant-aurora-D6GsdTPA.js} +2 -2
  279. package/dist/{variant-aurora-CcuDMWwQ.js → variant-aurora-DbW_OWL2.js} +1 -1
  280. package/dist/{elements/chunks/variant-custom-tJp22_BQ.js → variant-custom-BRvaNHSi.js} +1 -1
  281. package/dist/{variant-custom-L16JLLZy.js → variant-custom-BvYHR62b.js} +1 -1
  282. package/dist/{variant-custom-BdvYC7af.js → variant-custom-DMTrEO5w.js} +2 -2
  283. package/dist/{variant-custom-C714mqKl.js → variant-custom-DV2x254s.js} +2 -2
  284. package/dist/{variant-wave-ecwykeyL.js → variant-wave-BNMGrDfj.js} +2 -2
  285. package/dist/{variant-wave-2S4La2Ka.js → variant-wave-BpDd8t3Z.js} +1 -1
  286. package/dist/{variant-wave-D7ruiA1W.js → variant-wave-CyBueXj9.js} +2 -2
  287. package/dist/{elements/chunks/variant-wave-CaQ5ti39.js → variant-wave-sp-qwsdI.js} +1 -1
  288. package/dist/vue-BmIZj4XD.js +1 -33
  289. package/dist/x-Z5UntkIJ.js +1 -0
  290. package/frameworks/react/index.tsx +210 -22
  291. package/llms-full.txt +1184 -22
  292. package/llms.txt +6 -3
  293. package/package.json +17 -4
  294. package/src/agent-tooling/README.md +192 -0
  295. package/src/agent-tooling/catalog/invariants.ts +3 -3
  296. package/src/agent-tooling/catalog/surfaces.ts +72 -0
  297. package/src/agent-tooling/construct/cli-entry.ts +8 -0
  298. package/src/agent-tooling/construct/cli.ts +147 -0
  299. package/src/agent-tooling/construct/codegen.ts +1635 -0
  300. package/src/agent-tooling/construct/construct.v1.schema.json +319 -0
  301. package/src/agent-tooling/construct/dev.ts +148 -0
  302. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +7 -0
  303. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +44 -0
  304. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +32 -0
  305. package/src/agent-tooling/construct/schema.ts +452 -0
  306. package/src/agent-tooling/mcp/server.ts +2 -1
  307. package/src/agent-tooling/mcp/tools/construct.ts +130 -0
  308. package/src/agent-tooling/mcp/tools/debug.ts +126 -4
  309. package/src/agent-tooling/mcp/tools/reference.ts +104 -3
  310. package/src/agent-tooling/recipes/composed-thread.ts +714 -0
  311. package/src/agent-tooling/recipes/index.ts +22 -0
  312. package/src/agent-tooling/recipes/types.ts +32 -0
  313. package/src/agent-tooling/registry.ts +5 -0
  314. package/src/components/attachment-types.ts +7 -0
  315. package/src/components/audio-visualizer/fit-scale.ts +1 -1
  316. package/src/components/card-renderer.tsx +39 -8
  317. package/src/components/card.tsx +10 -2
  318. package/src/components/chat-scope-picker.tsx +2 -2
  319. package/src/components/chat-thread.tsx +602 -43
  320. package/src/components/choice-card.tsx +102 -37
  321. package/src/components/coachmark.tsx +1 -1
  322. package/src/components/code-block.tsx +2 -2
  323. package/src/components/composer.tsx +89 -15
  324. package/src/components/confirm-card.tsx +20 -4
  325. package/src/components/conversation-item.tsx +56 -9
  326. package/src/components/conversation-list.tsx +25 -10
  327. package/src/components/conversation-panel.tsx +118 -0
  328. package/src/components/empty.tsx +14 -3
  329. package/src/components/file-tree.tsx +5 -1
  330. package/src/components/form-widgets.tsx +257 -195
  331. package/src/components/form.tsx +297 -9
  332. package/src/components/home-panel.tsx +159 -0
  333. package/src/components/loader.tsx +12 -5
  334. package/src/components/message-skills.tsx +1 -1
  335. package/src/components/message.tsx +71 -11
  336. package/src/components/prompt-input.tsx +7 -1
  337. package/src/components/prompt-suggestion.tsx +4 -1
  338. package/src/components/reasoning.tsx +30 -3
  339. package/src/components/response-compare.tsx +2 -2
  340. package/src/components/scroll-button.tsx +56 -4
  341. package/src/components/source.tsx +6 -1
  342. package/src/components/tasks-card.tsx +58 -16
  343. package/src/components/thread.tsx +10 -1
  344. package/src/components/toast.tsx +1 -1
  345. package/src/components/tool-types.ts +9 -0
  346. package/src/components/widget-tab-bar.tsx +73 -0
  347. package/src/elements/attachments.tsx +3 -1
  348. package/src/elements/chat-workspace.tsx +1 -1
  349. package/src/elements/chat.tsx +115 -5
  350. package/src/elements/checkbox-group.tsx +164 -0
  351. package/src/elements/checkbox.tsx +134 -0
  352. package/src/elements/compiled.css +1 -1
  353. package/src/elements/composer.tsx +12 -1
  354. package/src/elements/conversation-item.tsx +62 -22
  355. package/src/elements/conversation-list.tsx +2 -2
  356. package/src/elements/define-entry.ts +12 -0
  357. package/src/elements/dock.tsx +11 -0
  358. package/src/elements/element-data-types.ts +40 -0
  359. package/src/elements/element-manifest.json +24 -0
  360. package/src/elements/element-meta.json +767 -34
  361. package/src/elements/element-nonscalar.json +17 -0
  362. package/src/elements/element-types.d.ts +380 -26
  363. package/src/elements/feedback-bar.tsx +5 -0
  364. package/src/elements/icon-names.json +29 -0
  365. package/src/elements/input.tsx +312 -23
  366. package/src/elements/message.tsx +2 -0
  367. package/src/elements/pane-grid.tsx +111 -0
  368. package/src/elements/prompt-input.tsx +8 -2
  369. package/src/elements/radio-group.tsx +129 -0
  370. package/src/elements/register-impl.ts +6 -0
  371. package/src/elements/scroll-button.tsx +54 -6
  372. package/src/elements/select.tsx +165 -0
  373. package/src/elements/slider.tsx +171 -0
  374. package/src/elements/slots.ts +1 -1
  375. package/src/elements/styles.css +89 -3
  376. package/src/elements/thread.tsx +2 -0
  377. package/src/elements/toast.tsx +14 -1
  378. package/src/index.ts +5 -2
  379. package/src/primitives/card-data-types.ts +49 -0
  380. package/src/primitives/card-host.tsx +4 -2
  381. package/src/primitives/card-routing.ts +7 -56
  382. package/src/primitives/card-schemas/form.schema.json +21 -1
  383. package/src/primitives/card-validate.ts +10 -2
  384. package/src/primitives/chat-config.tsx +33 -6
  385. package/src/primitives/conversation-store.ts +248 -0
  386. package/src/primitives/field-mask.ts +256 -0
  387. package/src/primitives/field-semantics.ts +115 -0
  388. package/src/primitives/input-mask.ts +853 -0
  389. package/src/primitives/toast-store.ts +66 -4
  390. package/src/primitives/url-scheme-policy.ts +70 -0
  391. package/src/primitives/use-resize-observer.ts +2 -2
  392. package/src/schemas/tool-defs.ts +12 -2
  393. package/src/solid.ts +20 -2
  394. package/src/state/index.ts +1 -1
  395. package/src/state/mock.ts +92 -6
  396. package/src/types.ts +45 -3
  397. package/src/ui/agent-card.tsx +2 -2
  398. package/src/ui/avatar.tsx +1 -1
  399. package/src/ui/checkbox-group.tsx +153 -0
  400. package/src/ui/checkbox.tsx +63 -0
  401. package/src/ui/dock.tsx +192 -7
  402. package/src/ui/icon.tsx +53 -0
  403. package/src/ui/input.tsx +249 -9
  404. package/src/ui/kbd.tsx +1 -1
  405. package/src/ui/nav.tsx +1 -1
  406. package/src/ui/pane-group.tsx +2 -2
  407. package/src/ui/radio.tsx +150 -0
  408. package/src/ui/select.tsx +168 -0
  409. package/src/ui/slider.tsx +178 -0
  410. package/src/ui/switch.tsx +49 -18
  411. package/src/utils/cn.ts +11 -5
  412. package/theme.css +112 -13
  413. package/dist/elements/chunks/action-icons-D9u3OzYW.js +0 -1
  414. package/dist/elements/chunks/arrow-left-CVh1TeN7.js +0 -1
  415. package/dist/elements/chunks/artifact-BkYcfIlZ.js +0 -1
  416. package/dist/elements/chunks/attachments-DwfNlubq.js +0 -1
  417. package/dist/elements/chunks/badge-Q0-Cmwzz.js +0 -1
  418. package/dist/elements/chunks/bash-InADTalH.js +0 -1
  419. package/dist/elements/chunks/card-renderer-3Dyl-FpN.js +0 -1
  420. package/dist/elements/chunks/card-routing-BK09BdmL.js +0 -1
  421. package/dist/elements/chunks/check-B5kBPKeo.js +0 -1
  422. package/dist/elements/chunks/chevron-down-DZ1GS39h.js +0 -1
  423. package/dist/elements/chunks/chevron-right-CvP7OUd2.js +0 -1
  424. package/dist/elements/chunks/choice-card-D4QUIOWZ.js +0 -1
  425. package/dist/elements/chunks/circle-CDf9g6MQ.js +0 -1
  426. package/dist/elements/chunks/circle-check-CA47Nqbz.js +0 -1
  427. package/dist/elements/chunks/circle-x-CJ_HVbC8.js +0 -1
  428. package/dist/elements/chunks/code-block-BdLiTitd.js +0 -1
  429. package/dist/elements/chunks/composer-Byve-n8K.js +0 -69
  430. package/dist/elements/chunks/confirm-card-B0flE3MN.js +0 -1
  431. package/dist/elements/chunks/controllable-DTwTIlwp.js +0 -1
  432. package/dist/elements/chunks/conversation-item-BDztezOG.js +0 -1
  433. package/dist/elements/chunks/copy-Nf-kqxXH.js +0 -1
  434. package/dist/elements/chunks/core-AYMC6_lb.js +0 -12
  435. package/dist/elements/chunks/css-M7EaDHN_.js +0 -1
  436. package/dist/elements/chunks/default-input-C2iLFq0b.js +0 -1
  437. package/dist/elements/chunks/define-wjHR1MkU.js +0 -1
  438. package/dist/elements/chunks/download-C4V7tBdb.js +0 -1
  439. package/dist/elements/chunks/embed-D3KewsIJ.js +0 -1
  440. package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +0 -141
  441. package/dist/elements/chunks/file-text-D1G8khle.js +0 -1
  442. package/dist/elements/chunks/folder-WW2LGLid.js +0 -1
  443. package/dist/elements/chunks/form-CQirdC4W.js +0 -1
  444. package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +0 -1
  445. package/dist/elements/chunks/github-light-JYsPkUQd.js +0 -1
  446. package/dist/elements/chunks/hover-card-CJJkfHTK.js +0 -1
  447. package/dist/elements/chunks/html-CPZ3oZQ7.js +0 -1
  448. package/dist/elements/chunks/icon-Cfgmf4fa.js +0 -1
  449. package/dist/elements/chunks/info-DX3YMOt6.js +0 -1
  450. package/dist/elements/chunks/input-BtW9U6Sq.js +0 -1
  451. package/dist/elements/chunks/javascript-C25yR2R2.js +0 -1
  452. package/dist/elements/chunks/json-DxJze_jm.js +0 -1
  453. package/dist/elements/chunks/kbd-LGXwuT_V.js +0 -1
  454. package/dist/elements/chunks/link-2My69BqT.js +0 -1
  455. package/dist/elements/chunks/loader-iOxc_Tu-.js +0 -1
  456. package/dist/elements/chunks/message-VMZohrXx.js +0 -1
  457. package/dist/elements/chunks/message-circle-CpXMM-_n.js +0 -1
  458. package/dist/elements/chunks/message-square-DxcWtETQ.js +0 -1
  459. package/dist/elements/chunks/message-tZmV2A3p.js +0 -1
  460. package/dist/elements/chunks/paperclip-CRZVp4z_.js +0 -1
  461. package/dist/elements/chunks/progress-bar-DNy66e_E.js +0 -1
  462. package/dist/elements/chunks/prompt-suggestion-Bn64Nl7L.js +0 -1
  463. package/dist/elements/chunks/reasoning-Emn9N4-T.js +0 -1
  464. package/dist/elements/chunks/rotate-cw-CPWe37D9.js +0 -1
  465. package/dist/elements/chunks/scroll-area-ClZkZxIk.js +0 -1
  466. package/dist/elements/chunks/scroll-button-DPE-t3x_.js +0 -1
  467. package/dist/elements/chunks/share-CyfnNEqp.js +0 -1
  468. package/dist/elements/chunks/source-UWCvmVak.js +0 -1
  469. package/dist/elements/chunks/star-DoHFAikQ.js +0 -1
  470. package/dist/elements/chunks/store-Cjq0qwYN.js +0 -1
  471. package/dist/elements/chunks/svelte--5p79yCD.js +0 -1
  472. package/dist/elements/chunks/tasks-card-CmZ5xh6v.js +0 -1
  473. package/dist/elements/chunks/text-shimmer-DYn09zrz.js +0 -1
  474. package/dist/elements/chunks/textarea-skiGHURM.js +0 -1
  475. package/dist/elements/chunks/toast-store-CFnQpThX.js +0 -1
  476. package/dist/elements/chunks/tsx-B8rCNbgL.js +0 -1
  477. package/dist/elements/chunks/typescript-RycA9KXf.js +0 -1
  478. package/dist/elements/chunks/use-card-resolution-DoA2f_EU.js +0 -1
  479. package/dist/elements/chunks/vue-BmIZj4XD.js +0 -1
  480. package/dist/elements/chunks/x-B6UnOiLw.js +0 -1
  481. package/dist/llms/llms-full.txt +0 -2949
  482. package/dist/llms/llms.txt +0 -156
  483. package/dist/register-impl-DpE7icIb.js +0 -293
  484. package/dist/ui/stat.d.ts +0 -16
  485. package/src/ui/stat.tsx +0 -41
  486. /package/dist/{elements/chunks/card-tags-D8lZ-C_U.js → card-tags-D8lZ-C_U.js} +0 -0
  487. /package/dist/{elements/chunks/link-preview-DNILK391.js → link-preview-DNILK391.js} +0 -0
  488. /package/dist/{elements/chunks/slots-DaNjX0rc.js → slots-DaNjX0rc.js} +0 -0
@@ -0,0 +1,63 @@
1
+ import { type JSX, splitProps, createEffect } from 'solid-js';
2
+ import { cn } from '../utils/cn';
3
+
4
+ export interface CheckboxProps extends Omit<JSX.InputHTMLAttributes<HTMLInputElement>, 'type' | 'children'> {
5
+ /**
6
+ * The mixed / partially-checked state ("some of the things below are ticked").
7
+ *
8
+ * `indeterminate` is a DOM PROPERTY with no HTML attribute, so it cannot be set
9
+ * from markup — every caller that wanted it used to reach for a `ref` plus a
10
+ * `createEffect`. That effect now lives in here, once, and callers pass a prop.
11
+ *
12
+ * Note that the property is purely visual plus an accessibility hint: a checkbox
13
+ * whose `indeterminate` is true still reports `checked === false` and submits
14
+ * accordingly. A native indeterminate checkbox already announces as "mixed", so
15
+ * this component does not stamp `aria-checked="mixed"` on top of it — pass one
16
+ * yourself if you also want the attribute in the DOM.
17
+ */
18
+ indeterminate?: boolean;
19
+ }
20
+
21
+ /**
22
+ * A checkbox. A REAL `<input type="checkbox">` behind `appearance: none`, styled by
23
+ * the kit's `.kai-checkbox` rule, never a `<div>` wearing `role="checkbox"`.
24
+ *
25
+ * That is the whole design: the native control brings keyboard operation (Space),
26
+ * the `:focus-visible` ring, form participation via `name` / `value`, and correct
27
+ * screen-reader announcement — all of it for free and all of it correct. Every
28
+ * accessibility defect this kit's control audit found was in a control that had
29
+ * replaced the native element with something hand-rolled.
30
+ *
31
+ * Everything not listed in `CheckboxProps` is forwarded to the input, so `id`,
32
+ * `name`, `value`, `required`, `disabled`, `aria-*` and any `data-*` hook behave
33
+ * exactly as they do on a plain `<input>`.
34
+ *
35
+ * Validation is deliberately absent. `required` is passed through to the native
36
+ * attribute and nothing else — whether an unchecked box is an error is the
37
+ * consuming application's call, not the kit's.
38
+ *
39
+ * ```tsx
40
+ * <Checkbox name="notify" checked={on()} onChange={(e) => setOn(e.currentTarget.checked)} />
41
+ * ```
42
+ */
43
+ export function Checkbox(props: CheckboxProps): JSX.Element {
44
+ const [local, rest] = splitProps(props, ['class', 'indeterminate', 'ref']);
45
+ return (
46
+ <input
47
+ {...rest}
48
+ type="checkbox"
49
+ class={cn('kai-checkbox', local.class)}
50
+ ref={(el) => {
51
+ // `ref` is split out and re-applied by hand because this component needs the
52
+ // element for `indeterminate` as well. Solid always hands a component a ref
53
+ // FUNCTION (a variable ref compiles into one), so the typeof guard is for the
54
+ // hand-written object case only.
55
+ const forward = local.ref;
56
+ if (typeof forward === 'function') (forward as (el: HTMLInputElement) => void)(el);
57
+ createEffect(() => {
58
+ el.indeterminate = !!local.indeterminate;
59
+ });
60
+ }}
61
+ />
62
+ );
63
+ }
package/src/ui/dock.tsx CHANGED
@@ -42,6 +42,19 @@ export interface DockProps {
42
42
  unread?: boolean;
43
43
  /** Disable the launcher. */
44
44
  disabled?: boolean;
45
+ /** Suppress the dock's own built-in mobile `[part="close"]` X. Off (rendered) by
46
+ * default — the built-in X is the FALLBACK close route for panel content with no
47
+ * header of its own, which is the general case the dock has to cover since it
48
+ * never reads what it holds. Set `true` when the slotted/composed content
49
+ * supplies its own close affordance in its own header row (e.g. `ChatThread`'s
50
+ * `headerEndContent`) — with both present the two X's stack, one floating over
51
+ * the other's row, which is exactly the "doesn't look intentional" feedback this
52
+ * prop exists to let a caller avoid. TRADEOFF: the mobile panel reserves a
53
+ * padding band above its content so the built-in X never paints over it; that
54
+ * band stays reserved unless you set `hideClose` true, so only set it once your
55
+ * own control is actually in place — otherwise you get the band with no X to
56
+ * justify it. */
57
+ hideClose?: boolean;
45
58
  /** Where focus lands on open. Defaults to `content`. */
46
59
  focusOnOpen?: DockFocusOnOpen;
47
60
  /** Controlled open state. When set, the component never changes it itself — drive it
@@ -79,6 +92,52 @@ export function DockCloseGlyph(): JSX.Element {
79
92
  return <X size={24} />;
80
93
  }
81
94
 
95
+ export interface DockLauncherImageProps {
96
+ /** The icon URL. */
97
+ src: string;
98
+ /** Alt text — usually left empty: the launcher BUTTON already carries the
99
+ * accessible name (Dock derives it from `label`/`openLabel`/`closeLabel`),
100
+ * so a second name on the icon inside it would be redundant, not missing. */
101
+ alt?: string;
102
+ }
103
+
104
+ /**
105
+ * A branded launcher icon with a built-in fallback to {@link DockLauncherGlyph}
106
+ * on load failure — a dead link, or a placeholder URL nobody swapped for a
107
+ * real asset yet (exactly what shipped in `kai dev`'s own `owner-widget`
108
+ * fixture: `launcherIcon: "https://example.com/logo.png"`, which never
109
+ * resolves, so the FAB rendered a permanently broken image). Decides loudly
110
+ * with one `console.warn` naming the failing URL, then swaps — never a
111
+ * silent broken-image icon sitting in the corner of someone's page.
112
+ *
113
+ * Lives here, not on {@link Dock} itself: `Dock`'s `launcher` prop is
114
+ * deliberately ANY content (an emoji, a "Support" text pill, this image,
115
+ * whatever a consumer slots in) and the dock never inspects what it's
116
+ * holding — teaching it to specifically understand "this might be an
117
+ * `<img>` that can 404" would be the one prop where that boundary breaks.
118
+ * This is a plain sibling component a `launcher` value can be built FROM,
119
+ * same relationship `DockLauncherGlyph`/`DockCloseGlyph` already have to
120
+ * `Dock`. The construct engine's `emitDockLauncher` (codegen.ts) renders
121
+ * `<DockLauncherImage src={...} />` for a construct-authored `launcherIcon`
122
+ * rather than hand-rolling the same onError dance in emitted output.
123
+ */
124
+ export function DockLauncherImage(props: DockLauncherImageProps) {
125
+ const [failed, setFailed] = createSignal(false);
126
+ return (
127
+ <Show when={!failed()} fallback={<DockLauncherGlyph />}>
128
+ <img
129
+ src={props.src}
130
+ alt={props.alt ?? ''}
131
+ style={{ width: '24px', height: '24px', 'border-radius': '9999px' }}
132
+ onError={() => {
133
+ console.warn(`[kai] Dock launcher icon failed to load (${props.src}); falling back to the default glyph.`);
134
+ setFailed(true);
135
+ }}
136
+ />
137
+ </Show>
138
+ );
139
+ }
140
+
82
141
  /**
83
142
  * The dock's own stylesheet, scoped to its shadow root.
84
143
  *
@@ -139,7 +198,12 @@ const DOCK_CSS = `
139
198
  /* ABOVE the panel, always. At <=480px the panel goes fixed/inset:0 and it comes
140
199
  after the launcher in DOM order, so at z-index:auto it painted OVER the launcher
141
200
  and a touch user lost every pointer route to closing. Both reference
142
- implementations stacked the launcher over the panel for the same reason. */
201
+ implementations stacked the launcher over the panel for the same reason. The
202
+ launcher itself is now HIDDEN while the panel is open at that width (see the
203
+ <=480px block below) in favour of the in-panel [part="close"] X, but this
204
+ z-index still matters for the moment between "open" landing and the panel's
205
+ own transition finishing, and for any consumer CSS that reintroduces the
206
+ launcher there. */
143
207
  z-index: 1;
144
208
  flex: none;
145
209
  display: inline-flex;
@@ -168,6 +232,58 @@ const DOCK_CSS = `
168
232
  [data-kai-dock] [part="launcher"]:focus-visible { outline: 2px solid var(--color-ring); outline-offset: 2px; }
169
233
  [data-kai-dock] [part="launcher"]:disabled { opacity: 0.55; cursor: not-allowed; }
170
234
 
235
+ /* The mobile-only close affordance rendered INSIDE the panel. Hidden by default and
236
+ only switched on inside the <=480px media block below, alongside the rule that
237
+ hides the launcher while the panel is open at that width — same query drives both,
238
+ CSS-only, no JS viewport logic. Absolutely positioned against the panel, which is
239
+ the panel's own containing block once the narrow-viewport rule below sets it to
240
+ position: fixed.
241
+
242
+ The inset is a CONSUMER-OVERRIDABLE TOKEN, same idiom as every other geometry
243
+ value in this file (--kai-dock-width and friends). The dock is content-agnostic —
244
+ it never reads what is slotted into the panel — so it cannot know whether that
245
+ content renders its own trailing controls (a ChatThread header-end slot with
246
+ share/settings icons, say) in the same top-right corner.
247
+
248
+ The mobile block below reserves a BAND of the panel's own padding above whatever
249
+ is slotted, sized to this button's own footprint, so nothing paints under this X
250
+ by default -- verified fix (round 1) against a real ChatThread header-end slot
251
+ colliding with it at 375px. Owner feedback on the real widget (round 2): for a
252
+ construct with only a title in the header, that band read as a dead empty strip
253
+ with the X floating alone in it -- "that doesn't look like the empty component
254
+ either, lets do better." The actual fix composes instead of reserving space:
255
+ ChatThread now has its own headerEndContent escape hatch (see its prop doc) so a
256
+ caller puts the close control INSIDE the header row, sharing it with the title --
257
+ zero collision by construction, no band needed. hideClose on this component (see
258
+ its prop doc) then suppresses this built-in X for exactly that case, and the
259
+ band above is scoped to :not([data-hide-close]) so it comes off ONLY there --
260
+ every other consumer (anyone who hasn't opted into hideClose, including a
261
+ hand-authored dock with real header-end content) keeps the band, same as round 1
262
+ shipped, so the collision it fixed stays fixed for them. What remains here for
263
+ that default case is a plain absolute overlay, top-right of the panel, with
264
+ these consumer-overridable inset tokens for the rare case it should deliberately
265
+ sit in front of something (e.g. a single small badge). */
266
+ [data-kai-dock] [part="close"] {
267
+ display: none;
268
+ position: absolute;
269
+ inset-block-start: var(--kai-dock-close-inset-block, 0.75rem);
270
+ inset-inline-end: var(--kai-dock-close-inset-inline, 0.75rem);
271
+ z-index: 1;
272
+ align-items: center;
273
+ justify-content: center;
274
+ inline-size: 2.25rem;
275
+ block-size: 2.25rem;
276
+ padding: 0;
277
+ border: 0;
278
+ border-radius: 9999px;
279
+ background: var(--color-background);
280
+ color: var(--color-foreground);
281
+ box-shadow: 0 2px 8px -2px rgb(0 0 0 / 0.3);
282
+ cursor: pointer;
283
+ }
284
+ [data-kai-dock] [part="close"]:hover { background: var(--color-muted, var(--color-background)); }
285
+ [data-kai-dock] [part="close"]:focus-visible { outline: 2px solid var(--color-ring); outline-offset: 2px; }
286
+
171
287
  [data-kai-dock] [part="badge"] {
172
288
  position: absolute;
173
289
  inset-block-start: 3px;
@@ -175,7 +291,7 @@ const DOCK_CSS = `
175
291
  inline-size: 0.75rem;
176
292
  block-size: 0.75rem;
177
293
  border-radius: 9999px;
178
- background: var(--color-destructive);
294
+ background: var(--color-unread);
179
295
  box-shadow: 0 0 0 2px var(--color-primary);
180
296
  }
181
297
 
@@ -222,10 +338,12 @@ const DOCK_CSS = `
222
338
  [data-kai-dock][data-position^="top"] [part="panel"][data-closed] { transform: translateY(-0.5rem); }
223
339
 
224
340
  /* Narrow viewports take the panel full-bleed. A SHIPPED DEFAULT, not a prop: both
225
- references wrote this rule independently, which makes it a HOW. The launcher stays
226
- in its corner and ON TOP of the full-bleed panel that is the z-index: 1 in the
227
- launcher rule above, not anything in this block, and without it a phone user has no
228
- pointer route to closing at all (Escape alone strands exactly the touch user). */
341
+ references wrote this rule independently, which makes it a HOW. While the panel is
342
+ OPEN at this width the launcher hides and the panel's own [part="close"] X becomes
343
+ the pointer close route instead a FAB floating over a full-bleed panel read as
344
+ wrong (owner feedback) and Escape alone strands a touch user with no visible
345
+ affordance at all. Closed, the launcher is unaffected: it is the panel's own
346
+ [data-expanded] state that gates both rules below, not the media query alone. */
229
347
  @media (max-width: 480px) {
230
348
  [data-kai-dock] [part="panel"] {
231
349
  position: fixed;
@@ -237,6 +355,41 @@ const DOCK_CSS = `
237
355
  border: 0;
238
356
  border-radius: 0;
239
357
  }
358
+
359
+ /* Reserve a band for the built-in [part="close"] X ABOVE whatever is slotted,
360
+ rather than overlaying it on top of the panel's own content — the fix round 1
361
+ collision protection (verified against a real ChatThread header-end slot at
362
+ 375px: without this, the X painted directly over trailing icon buttons).
363
+ DERIVED from the button's own inset + size tokens, not a second hand-typed
364
+ number.
365
+
366
+ SCOPED to :not([data-hide-close]) — round 2 (owner feedback: the band read as
367
+ a dead strip when nothing but the X occupied it) removed this UNCONDITIONALLY
368
+ and reintroduced the very collision round 1 fixed, for every consumer who
369
+ never opted into hideClose. hideClose is only true for a caller that supplies
370
+ its OWN close control in its own header row (ChatThread's headerEndContent is
371
+ the one that does today) — the built-in X and this band both come off
372
+ together for that case, since there is nothing left for the band to protect.
373
+ Every other consumer -- including a hand-authored kai-dock with real
374
+ slot="header-end" content and no opinion on hideClose -- keeps the band, the
375
+ same as round 1 shipped. */
376
+ [data-kai-dock]:not([data-hide-close]) [part="panel"] {
377
+ padding-block-start: calc(2 * var(--kai-dock-close-inset-block, 0.75rem) + 2.25rem);
378
+ }
379
+
380
+ /* The full-bleed panel gets its own close affordance instead of relying on the
381
+ launcher, which is hidden below while the panel is open at this width — a FAB
382
+ floating over a full-bleed panel with no other visible close route is exactly
383
+ what the owner flagged. Escape and the X both still work; the launcher comes
384
+ back the instant the panel closes because data-expanded is gone by then.
385
+ Absolutely positioned, so the padding-block-start above (a content-box
386
+ concern) does not shift IT — only the in-flow slotted content. Content that
387
+ supplies its own close control passes hideClose, which drops the button from
388
+ the render tree entirely (see the component body) rather than being gated
389
+ here — so this rule stays a plain, unconditional width-query switch; the band
390
+ above is what actually varies with hideClose. */
391
+ [data-kai-dock] [part="close"] { display: inline-flex; }
392
+ [data-kai-dock]:has([part="panel"][data-expanded]) [part="launcher"] { display: none; }
240
393
  }
241
394
 
242
395
  @media (prefers-reduced-motion: reduce) {
@@ -310,6 +463,15 @@ function isWithin(root: Node, node: Node | null): boolean {
310
463
  * own menus; swallowing a key from a page you are a guest on is a decide-quietly move.
311
464
  * - **No focus trap**, deliberately, unlike `kai-dialog`. The page staying usable is
312
465
  * the whole point of "docked", which is also why the panel is `aria-modal="false"`.
466
+ * - **Mobile close route.** At <=480px the panel goes full-bleed and the launcher
467
+ * hides while it is open — a floating launcher over a full-bleed panel is not an
468
+ * obvious close affordance. The panel gets its own `[part="close"]` X, top-right,
469
+ * CSS-gated by the SAME media query and `[data-expanded]`, so it needs no viewport
470
+ * JS. Desktop is unaffected: the launcher keeps toggling and no X ever renders.
471
+ * This is the FALLBACK route, for panel content with no header of its own to hold
472
+ * a close control — content that does (a `ChatThread` using `headerEndContent`,
473
+ * say) passes `hideClose` to drop this X instead of stacking a second one over
474
+ * its own header row.
313
475
  *
314
476
  * WHAT IT REFUSES: it never aborts a request, never persists its own open state, never
315
477
  * decides what "unread" means, and never clears `unread` on open — writing over a
@@ -393,7 +555,17 @@ export function Dock(props: DockProps) {
393
555
  return (
394
556
  <>
395
557
  <style>{DOCK_CSS}</style>
396
- <div data-kai-dock data-position={props.position ?? 'bottom-end'} onKeyDown={onKeyDown}>
558
+ <div
559
+ data-kai-dock
560
+ data-position={props.position ?? 'bottom-end'}
561
+ // Drives the mobile panel's reserved-band rule below: present only when the
562
+ // built-in [part="close"] X is ACTUALLY suppressed (hideClose true), so the
563
+ // band stays on for every consumer who hasn't opted into their own close
564
+ // control — see the [part="close"]/reserved-band comments for why removing
565
+ // it unconditionally regressed the collision it existed to prevent.
566
+ bool:data-hide-close={!!props.hideClose}
567
+ onKeyDown={onKeyDown}
568
+ >
397
569
  <button
398
570
  ref={(el) => { launcher = el; props.launcherRef?.(el); }}
399
571
  part="launcher"
@@ -437,6 +609,19 @@ export function Dock(props: DockProps) {
437
609
  'pointer-events': isOpen() ? 'auto' : 'none',
438
610
  }}
439
611
  >
612
+ {/* Mobile-only (see the <=480px rule in DOCK_CSS): the full-bleed panel's
613
+ own close affordance, since the launcher is hidden by the same query
614
+ while the panel is open. Reuses the launcher's derived close name
615
+ rather than a new prop — same string, same i18n override. Dropped
616
+ from the render tree entirely (not just hidden) when `hideClose` is
617
+ set — the panel content supplies its own, in its own header, and a
618
+ second X floating over that row is the exact "doesn't look
619
+ intentional" feedback `hideClose` exists to avoid. */}
620
+ <Show when={!props.hideClose}>
621
+ <button type="button" part="close" aria-label={launcherName()} onClick={() => setOpen(false)}>
622
+ <DockCloseGlyph />
623
+ </button>
624
+ </Show>
440
625
  {props.children}
441
626
  </div>
442
627
  </div>
package/src/ui/icon.tsx CHANGED
@@ -9,6 +9,16 @@ import {
9
9
  Archive, ArrowUp, Bookmark, Copy, Ellipsis, ExternalLink, Flag,
10
10
  GitBranch, GitPullRequest, ListFilter, RotateCw,
11
11
  Moon, Sun,
12
+ // Device / viewport glyphs.
13
+ Tablet, Smartphone, Laptop,
14
+ // Direction glyphs completing the chevron + arrow quartets.
15
+ ChevronRight, ChevronUp, ArrowRight, ArrowDown, PanelRight,
16
+ // Status glyphs (kai-notice / kai-toast / kai-tool render these already).
17
+ Check, Info, TriangleAlert, CircleCheck, CircleAlert, CircleX,
18
+ // Action glyphs the kit performs but could not be named.
19
+ Trash2, Download, Upload, Link, RotateCcw,
20
+ // Pane / media chrome.
21
+ Maximize2, Minimize2, Eye, EyeOff, Bell, Square, Minus, Play,
12
22
  } from 'lucide-solid';
13
23
 
14
24
  type IconComponent = Component<{ class?: string }>;
@@ -68,8 +78,51 @@ const NAMED_ICONS: Record<string, IconComponent> = {
68
78
  // Theme / appearance glyphs.
69
79
  moon: Moon,
70
80
  sun: Sun,
81
+ // Device / viewport glyphs. `desktop` and `mobile` are aliases onto the same
82
+ // components as `monitor`/`smartphone` — lucide's names are not the words a
83
+ // consumer reaches for, and an alias costs nothing in the bundle.
84
+ desktop: Monitor,
85
+ laptop: Laptop,
86
+ tablet: Tablet,
87
+ smartphone: Smartphone,
88
+ mobile: Smartphone,
89
+ // Direction glyphs — chevron-down/left and arrow-left/up were here without
90
+ // their opposites; both quartets are now complete.
91
+ 'chevron-right': ChevronRight,
92
+ 'chevron-up': ChevronUp,
93
+ 'arrow-right': ArrowRight,
94
+ 'arrow-down': ArrowDown,
95
+ 'panel-right': PanelRight,
96
+ // Status glyphs. kai-notice / kai-toast / kai-tool already paint these, so a
97
+ // host building matching UI needs to be able to name them.
98
+ check: Check,
99
+ info: Info,
100
+ 'triangle-alert': TriangleAlert,
101
+ 'circle-check': CircleCheck,
102
+ 'circle-alert': CircleAlert,
103
+ 'circle-x': CircleX,
104
+ // Action glyphs. `trash`/`download`/`link` match the keys action-icons.ts
105
+ // already uses for message actions; `upload` is download's missing sibling.
106
+ trash: Trash2,
107
+ download: Download,
108
+ upload: Upload,
109
+ link: Link,
110
+ 'rotate-ccw': RotateCcw,
111
+ // Pane / media chrome (kai-pane, kai-artifact, kai-embed, kai-agent-card).
112
+ 'maximize-2': Maximize2,
113
+ 'minimize-2': Minimize2,
114
+ eye: Eye,
115
+ 'eye-off': EyeOff,
116
+ bell: Bell,
117
+ square: Square,
118
+ minus: Minus,
119
+ play: Play,
71
120
  };
72
121
 
122
+ /** Every curated icon name, sorted. Derived from `NAMED_ICONS` so a gallery,
123
+ * a story control or a test can never drift from the map itself. */
124
+ export const ICON_NAMES: readonly string[] = Object.keys(NAMED_ICONS).sort();
125
+
73
126
  /** Render an item icon.
74
127
  *
75
128
  * Resolution order: