@kitn.ai/ui 0.20.1 → 0.22.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 (510) hide show
  1. package/README.md +44 -45
  2. package/dist/components/artifact-card.d.ts +51 -0
  3. package/dist/components/artifact.d.ts +1 -1
  4. package/dist/components/attachments.d.ts +2 -2
  5. package/dist/components/audio-visualizer/index.d.ts +3 -3
  6. package/dist/components/audio-visualizer/labs/lab-choreography.d.ts +59 -0
  7. package/dist/components/audio-visualizer/labs/lab-shaders.d.ts +22 -0
  8. package/dist/components/audio-visualizer/labs/lab-visualizer.d.ts +18 -0
  9. package/dist/components/audio-visualizer/variant-aurora.d.ts +2 -2
  10. package/dist/components/audio-visualizer/variant-bar.d.ts +2 -2
  11. package/dist/components/audio-visualizer/variant-custom.d.ts +2 -2
  12. package/dist/components/audio-visualizer/variant-grid.d.ts +1 -1
  13. package/dist/components/audio-visualizer/variant-radial.d.ts +1 -1
  14. package/dist/components/audio-visualizer/variant-wave.d.ts +1 -1
  15. package/dist/components/card-fallback.d.ts +12 -2
  16. package/dist/components/card-renderer.d.ts +63 -2
  17. package/dist/components/chat-container.d.ts +3 -0
  18. package/dist/components/chat-scope-picker.d.ts +2 -2
  19. package/dist/components/chat-thread.d.ts +77 -18
  20. package/dist/components/choice-card.d.ts +3 -28
  21. package/dist/components/composer-dom.d.ts +1 -1
  22. package/dist/components/composer-highlight.d.ts +1 -1
  23. package/dist/components/composer-history.d.ts +1 -1
  24. package/dist/components/composer.d.ts +1 -1
  25. package/dist/components/confirm-card.d.ts +3 -18
  26. package/dist/components/context.d.ts +8 -4
  27. package/dist/components/conversation-item.d.ts +1 -1
  28. package/dist/components/conversation-list.d.ts +4 -3
  29. package/dist/components/embed.d.ts +3 -3
  30. package/dist/components/file-tree.d.ts +11 -22
  31. package/dist/components/form-widgets.d.ts +1 -1
  32. package/dist/components/form.d.ts +3 -44
  33. package/dist/components/link-preview.d.ts +3 -3
  34. package/dist/components/loader.d.ts +30 -48
  35. package/dist/components/message-skills.d.ts +4 -0
  36. package/dist/components/message.d.ts +84 -21
  37. package/dist/components/model-switcher.d.ts +2 -2
  38. package/dist/components/prompt-input.d.ts +2 -2
  39. package/dist/components/response-compare-types.d.ts +11 -2
  40. package/dist/components/response-compare.d.ts +3 -3
  41. package/dist/components/source.d.ts +12 -3
  42. package/dist/components/tasks-card.d.ts +3 -31
  43. package/dist/components/thread.d.ts +17 -5
  44. package/dist/components/toast.d.ts +2 -2
  45. package/dist/components/tool-classify.d.ts +8 -0
  46. package/dist/components/tool-types.d.ts +29 -1
  47. package/dist/components/tool.d.ts +3 -3
  48. package/dist/components/use-card-resolution.d.ts +1 -1
  49. package/dist/create-tween-COnPwAQN.js +338 -0
  50. package/dist/create-tween-DmTUaXWE.js +341 -0
  51. package/dist/create-tween-qs-jjvNA.js +7 -0
  52. package/dist/custom-elements.json +1726 -463
  53. package/dist/elements/agent-card.js +1 -1
  54. package/dist/elements/artifact.js +1 -1
  55. package/dist/elements/attachments.js +1 -1
  56. package/dist/elements/audio-visualizer.js +1 -1
  57. package/dist/elements/avatar.js +1 -1
  58. package/dist/elements/badge.js +1 -1
  59. package/dist/elements/button.js +1 -1
  60. package/dist/elements/card.js +1 -1
  61. package/dist/elements/cards.js +1 -1
  62. package/dist/elements/chain-of-thought.js +1 -1
  63. package/dist/elements/chat-scope-picker.js +1 -1
  64. package/dist/elements/chat-types.d.ts +70 -10
  65. package/dist/elements/chat-workspace.js +1 -1
  66. package/dist/elements/chat.js +1 -1
  67. package/dist/elements/checkpoint.js +1 -1
  68. package/dist/elements/choice.js +1 -1
  69. package/dist/elements/chunks/{Icon-Tj58ES_d.js → Icon-CHG5z5L7.js} +1 -1
  70. package/dist/elements/chunks/{action-icons-ns1Fnedj.js → action-icons-BAtCEEgg.js} +1 -1
  71. package/dist/elements/chunks/arrow-left-CFPTeL1Y.js +1 -0
  72. package/dist/elements/chunks/artifact-fBZOE4SO.js +1 -0
  73. package/dist/elements/chunks/{attachments-mCB5F1Fq.js → attachments-DpYMe5VQ.js} +1 -1
  74. package/dist/elements/chunks/audio-visualizer-DFwzAcuL.js +1 -0
  75. package/dist/elements/chunks/{badge-B4Zuajl2.js → badge-D6zodm6E.js} +1 -1
  76. package/dist/elements/chunks/{button-ZWNif3--.js → button-C42vrGvO.js} +1 -1
  77. package/dist/elements/chunks/card-renderer-DMZsSuvU.js +1 -0
  78. package/dist/elements/chunks/card-tags-D8lZ-C_U.js +1 -0
  79. package/dist/elements/chunks/chat-thread-CNNEhol-.js +1 -0
  80. package/dist/elements/chunks/check-7Q3K-iXE.js +1 -0
  81. package/dist/elements/chunks/chevron-down-CpNYLn7E.js +1 -0
  82. package/dist/elements/chunks/chevron-right-DrH85Fha.js +1 -0
  83. package/dist/elements/chunks/choice-card-YoWjpsFV.js +1 -0
  84. package/dist/elements/chunks/circle-C9KRjKYv.js +1 -0
  85. package/dist/elements/chunks/circle-check-Dmi7Y4zw.js +1 -0
  86. package/dist/elements/chunks/{circle-x-B7faJFlY.js → circle-x-QIxXda6k.js} +1 -1
  87. package/dist/elements/chunks/code-block-CqeugReY.js +1 -0
  88. package/dist/elements/chunks/{collapsible-DM1Ckd4e.js → collapsible-sTv-_5lF.js} +1 -1
  89. package/dist/elements/chunks/{composer-BguS0QL_.js → composer-ldQyeVEB.js} +2 -2
  90. package/dist/elements/chunks/confirm-card-C0RNOwfn.js +1 -0
  91. package/dist/elements/chunks/context-5qgypNHC.js +1 -0
  92. package/dist/elements/chunks/conversation-list-DLzOacXz.js +1 -0
  93. package/dist/elements/chunks/create-tween-V4TXZ93X.js +7 -0
  94. package/dist/elements/chunks/default-input-DeeRSDHc.js +1 -0
  95. package/dist/elements/chunks/define-lE-QvQFn.js +1 -0
  96. package/dist/elements/chunks/{disclosure-CIZ5c8nO.js → disclosure-DZSa9jog.js} +1 -1
  97. package/dist/elements/chunks/{download-Dsbg3ste.js → download-B2ZmnGqW.js} +1 -1
  98. package/dist/elements/chunks/{dropdown-BDd1-Zgi.js → dropdown-R3B7cSRE.js} +1 -1
  99. package/dist/elements/chunks/{ellipsis-Dw6qrss-.js → ellipsis-BmxceY4l.js} +1 -1
  100. package/dist/elements/chunks/embed-BVrtTZPo.js +1 -0
  101. package/dist/elements/chunks/{external-link-Vt74zAoL.js → external-link-BbdR7YO7.js} +1 -1
  102. package/dist/elements/chunks/{file-text-CZrZF6_v.js → file-text-D7dijo1A.js} +1 -1
  103. package/dist/elements/chunks/{file-tree-DF4okKyo.js → file-tree-0upJ5jeb.js} +1 -1
  104. package/dist/elements/chunks/{folder-glP5rha4.js → folder-D8z58t7B.js} +1 -1
  105. package/dist/elements/chunks/form-p5BKJNw5.js +1 -0
  106. package/dist/elements/chunks/hover-card-CN9s2md5.js +1 -0
  107. package/dist/elements/chunks/{icon-BLb8beoi.js → icon-CNiKP37E.js} +1 -1
  108. package/dist/elements/chunks/{info-CIsv92JK.js → info-BSnuJiHI.js} +1 -1
  109. package/dist/elements/chunks/{input-Dds1kFyt.js → input-BauDmzxX.js} +1 -1
  110. package/dist/elements/chunks/{kbd-De_xbgi9.js → kbd-BlHJaP9b.js} +1 -1
  111. package/dist/elements/chunks/{link-i4r_k7z4.js → link-DEi5iUWC.js} +1 -1
  112. package/dist/elements/chunks/link-preview-BaHyM6W4.js +1 -0
  113. package/dist/elements/chunks/{loader-BmQH4s3V.js → loader-CmJG_Fkq.js} +1 -1
  114. package/dist/elements/chunks/{markdown-Zi21WhUz.js → markdown-D2jaMpCN.js} +1 -1
  115. package/dist/elements/chunks/message-C5UfXZ2Z.js +1 -0
  116. package/dist/elements/chunks/message-CXWLmmLn.js +1 -0
  117. package/dist/elements/chunks/message-square-hXylwsy0.js +1 -0
  118. package/dist/elements/chunks/{minimize-2--ifeCGrl.js → minimize-2-C9ytZFMU.js} +1 -1
  119. package/dist/elements/chunks/model-switcher-CivGfD7-.js +1 -0
  120. package/dist/elements/chunks/{overlay-kD8dwRv_.js → overlay-DJL_sbOm.js} +1 -1
  121. package/dist/elements/chunks/{paperclip-q21dYOSK.js → paperclip-CFaB8naM.js} +1 -1
  122. package/dist/elements/chunks/{progress-bar-BrAIIaaJ.js → progress-bar-Br5SksfR.js} +1 -1
  123. package/dist/elements/chunks/{prompt-suggestion-Bjn2K-fR.js → prompt-suggestion-CMIvtAhU.js} +1 -1
  124. package/dist/elements/chunks/reasoning-DpZcNzLq.js +1 -0
  125. package/dist/elements/chunks/{resizable-Dp4JExql.js → resizable-Q8i3T9a_.js} +1 -1
  126. package/dist/elements/chunks/{rotate-cw-CFWWkpj2.js → rotate-cw-B5IHCBFV.js} +1 -1
  127. package/dist/elements/chunks/{scroll-area-Bb0kHH1j.js → scroll-area-eLeydBje.js} +1 -1
  128. package/dist/elements/chunks/scroll-button-DWbz0yA1.js +1 -0
  129. package/dist/elements/chunks/{separator-9kRgr1X9.js → separator-Xic78AD_.js} +1 -1
  130. package/dist/elements/chunks/{settings-B8lmec4D.js → settings-B8H51pAx.js} +1 -1
  131. package/dist/elements/chunks/{settings-group-I0hEuXiN.js → settings-group-CsG9eYLe.js} +1 -1
  132. package/dist/elements/chunks/{share-C3lTiYGt.js → share-CNTx0z__.js} +1 -1
  133. package/dist/elements/chunks/skeleton-CLlHTcMI.js +1 -0
  134. package/dist/elements/chunks/slots-CIw9RlAe.js +1 -0
  135. package/dist/elements/chunks/source-BoVcU5ok.js +1 -0
  136. package/dist/elements/chunks/{star-CSJtGxgv.js → star-CxQVTVhI.js} +1 -1
  137. package/dist/elements/chunks/{store-CHyW95TP.js → store-CLtS5CUG.js} +1 -1
  138. package/dist/elements/chunks/tasks-card-CzlkLmUt.js +1 -0
  139. package/dist/elements/chunks/{text-shimmer-Cn9TmNpI.js → text-shimmer-D5NhpIQ1.js} +1 -1
  140. package/dist/elements/chunks/textarea-x5Uxsmtm.js +1 -0
  141. package/dist/elements/chunks/{thumbs-up-PNVVThEF.js → thumbs-up-UobcJnx9.js} +1 -1
  142. package/dist/elements/chunks/{toast-store-DKbQn3Wn.js → toast-store-BOfs9eXq.js} +1 -1
  143. package/dist/elements/chunks/{tool-DjTRpIpl.js → tool-Be6Dh_dt.js} +1 -1
  144. package/dist/elements/chunks/tooltip-RxMxyCLF.js +1 -0
  145. package/dist/elements/chunks/{triangle-alert-DsHTHCPm.js → triangle-alert-C4yxH2XN.js} +1 -1
  146. package/dist/elements/chunks/use-card-resolution-jva9ehH6.js +1 -0
  147. package/dist/elements/chunks/{variant-aurora-Dc4nQUia.js → variant-aurora-Dx4VRcjS.js} +2 -2
  148. package/dist/elements/chunks/{variant-custom-y_3kVQhS.js → variant-custom-Y1ZTWgEa.js} +1 -1
  149. package/dist/elements/chunks/{variant-wave-D5OR1-9Z.js → variant-wave-B9gml9Cg.js} +2 -2
  150. package/dist/elements/chunks/{video-B7vmenoC.js → video-CrPHsytT.js} +1 -1
  151. package/dist/elements/chunks/x-_-OPHept.js +1 -0
  152. package/dist/elements/coachmark.js +1 -1
  153. package/dist/elements/code-block.js +1 -1
  154. package/dist/elements/command.js +1 -1
  155. package/dist/elements/compare.js +1 -1
  156. package/dist/elements/composer.js +1 -1
  157. package/dist/elements/confirm-card.js +1 -1
  158. package/dist/elements/context-meter.js +1 -1
  159. package/dist/elements/conversation-list.js +1 -1
  160. package/dist/elements/default-input.d.ts +34 -7
  161. package/dist/elements/define.d.ts +1 -0
  162. package/dist/elements/dialog.js +1 -1
  163. package/dist/elements/disclosure.d.ts +1 -1
  164. package/dist/elements/editable-label.js +1 -1
  165. package/dist/elements/element-data-types.d.ts +107 -0
  166. package/dist/elements/embed.js +1 -1
  167. package/dist/elements/empty.js +1 -1
  168. package/dist/elements/feedback-bar.js +1 -1
  169. package/dist/elements/file-tree.js +1 -1
  170. package/dist/elements/file-upload.js +1 -1
  171. package/dist/elements/form.js +1 -1
  172. package/dist/elements/hover-card.js +1 -1
  173. package/dist/elements/icon.js +1 -1
  174. package/dist/elements/image.js +1 -1
  175. package/dist/elements/input.js +1 -1
  176. package/dist/elements/kbd.js +1 -1
  177. package/dist/elements/link-preview.js +1 -1
  178. package/dist/elements/loader.js +1 -1
  179. package/dist/elements/markdown.js +1 -1
  180. package/dist/elements/menu.js +1 -1
  181. package/dist/elements/message-skills.js +1 -1
  182. package/dist/elements/message.js +1 -1
  183. package/dist/elements/model-switcher.js +1 -1
  184. package/dist/elements/nav.js +1 -1
  185. package/dist/elements/notice.js +1 -1
  186. package/dist/elements/pane-group.js +1 -1
  187. package/dist/elements/pane.js +1 -1
  188. package/dist/elements/popover.js +1 -1
  189. package/dist/elements/progress-bar.js +1 -1
  190. package/dist/elements/prompt-dock.js +1 -1
  191. package/dist/elements/prompt-input.js +1 -1
  192. package/dist/elements/prompt-suggestions.js +1 -1
  193. package/dist/elements/reasoning.js +1 -1
  194. package/dist/elements/register.d.ts +8 -6
  195. package/dist/elements/remote.js +1 -1
  196. package/dist/elements/resizable.js +1 -1
  197. package/dist/elements/response-stream.js +1 -1
  198. package/dist/elements/screen.js +1 -1
  199. package/dist/elements/scroll-area.js +1 -1
  200. package/dist/elements/scroll-button.js +1 -1
  201. package/dist/elements/search.js +1 -1
  202. package/dist/elements/segmented.js +1 -1
  203. package/dist/elements/separator.js +1 -1
  204. package/dist/elements/setting-item.js +1 -1
  205. package/dist/elements/settings-group.js +1 -1
  206. package/dist/elements/skeleton.js +1 -1
  207. package/dist/elements/slot-text.d.ts +51 -0
  208. package/dist/elements/slots.d.ts +21 -0
  209. package/dist/elements/source.js +1 -1
  210. package/dist/elements/status.js +1 -1
  211. package/dist/elements/switch.js +1 -1
  212. package/dist/elements/tabs.js +1 -1
  213. package/dist/elements/tasks.js +1 -1
  214. package/dist/elements/text-shimmer.js +1 -1
  215. package/dist/elements/thinking-bar.js +1 -1
  216. package/dist/elements/thread.js +1 -1
  217. package/dist/elements/toast.js +1 -1
  218. package/dist/elements/tool.js +1 -1
  219. package/dist/elements/tooltip.js +1 -1
  220. package/dist/elements/validate-messages.d.ts +25 -0
  221. package/dist/elements/voice-input.js +1 -1
  222. package/dist/elements/voice-output.js +1 -1
  223. package/dist/elements.d.ts +2734 -217
  224. package/dist/index.d.ts +163 -125
  225. package/dist/index.js +6572 -5990
  226. package/dist/index.server.d.ts +5 -0
  227. package/dist/index.server.js +5403 -4860
  228. package/dist/kai-provider.es.d.ts +5 -0
  229. package/dist/kai-provider.es.js +79 -77
  230. package/dist/kai.es.d.ts +5 -0
  231. package/dist/kai.es.js +1 -1
  232. package/dist/llms/llms-full.txt +774 -151
  233. package/dist/llms/llms.txt +57 -5
  234. package/dist/mcp.es.js +4756 -782
  235. package/dist/primitives/card-component-types.d.ts +11 -0
  236. package/dist/primitives/card-data-types.d.ts +196 -0
  237. package/dist/primitives/card-host.d.ts +1 -1
  238. package/dist/primitives/card-recovery.d.ts +3 -3
  239. package/dist/primitives/card-registry.d.ts +4 -14
  240. package/dist/primitives/card-resolution.d.ts +1 -1
  241. package/dist/primitives/card-routing.d.ts +1 -1
  242. package/dist/primitives/card-tags.d.ts +11 -0
  243. package/dist/primitives/card-validate-cards.d.ts +57 -0
  244. package/dist/primitives/card-validate-generator.testlib.d.ts +20 -0
  245. package/dist/primitives/card-validate-schemas.d.ts +17 -0
  246. package/dist/primitives/card-validate.d.ts +24 -0
  247. package/dist/primitives/create-kai-chat.d.ts +3 -3
  248. package/dist/primitives/embed-providers.d.ts +1 -1
  249. package/dist/primitives/link-preview.d.ts +1 -1
  250. package/dist/primitives/message-feedback.d.ts +2 -2
  251. package/dist/primitives/toast-store.d.ts +1 -1
  252. package/dist/react/index.d.ts +730 -302
  253. package/dist/react/use-kai-chat.d.ts +8 -4
  254. package/dist/react.d.ts +5 -0
  255. package/dist/react.js +418 -317
  256. package/dist/register-impl-AxIlqjo7.js +145 -0
  257. package/dist/remote/host-embed.d.ts +1 -1
  258. package/dist/remote/index.d.ts +2 -2
  259. package/dist/remote/provider-runtime.d.ts +2 -2
  260. package/dist/remote/provider.d.ts +2 -2
  261. package/dist/remote/validate.d.ts +1 -1
  262. package/dist/remote/wire.d.ts +1 -1
  263. package/dist/schemas/artifact.schema.json +92 -0
  264. package/dist/schemas/embed.schema.json +0 -2
  265. package/dist/schemas/from-tool-call.d.ts +48 -0
  266. package/dist/schemas/index.d.ts +48 -0
  267. package/dist/schemas/link.schema.json +0 -2
  268. package/dist/schemas/provider-subsets.d.ts +136 -0
  269. package/dist/schemas/registry.d.ts +140 -0
  270. package/dist/schemas/tool-defs.d.ts +121 -0
  271. package/dist/schemas.d.ts +5 -0
  272. package/dist/schemas.js +717 -0
  273. package/dist/solid-BGYSJyHG.js +22960 -0
  274. package/dist/solid-Dt2nEwfl.js +20194 -0
  275. package/dist/solid.d.ts +66 -0
  276. package/dist/solid.js +261 -0
  277. package/dist/solid.server.d.ts +5 -0
  278. package/dist/solid.server.js +261 -0
  279. package/dist/state/index.d.ts +14 -4
  280. package/dist/state/messages.d.ts +8 -3
  281. package/dist/state/mock.d.ts +46 -0
  282. package/dist/state/parts.d.ts +85 -0
  283. package/dist/state/stream.d.ts +15 -9
  284. package/dist/state.d.ts +5 -0
  285. package/dist/state.js +253 -84
  286. package/dist/ui/action-icons.d.ts +1 -1
  287. package/dist/ui/collapsible.d.ts +11 -6
  288. package/dist/ui/dropdown.d.ts +47 -42
  289. package/dist/ui/pane-group.d.ts +1 -1
  290. package/dist/{variant-aurora-DVtGqVH6.js → variant-aurora-B44X69AG.js} +1 -1
  291. package/dist/variant-aurora-BRhV8Flk.js +391 -0
  292. package/dist/variant-aurora-Ds5ou9BH.js +381 -0
  293. package/dist/variant-custom-B20FhtYj.js +170 -0
  294. package/dist/{variant-custom-Dif-IV4u.js → variant-custom-BvA1Schl.js} +1 -1
  295. package/dist/variant-custom-D6Rtvneb.js +200 -0
  296. package/dist/{variant-wave-DbfNdvSi.js → variant-wave-BUQtkryq.js} +1 -1
  297. package/dist/variant-wave-BVYnqy9L.js +218 -0
  298. package/dist/variant-wave-DXC6_LcH.js +208 -0
  299. package/dist/wire/chunk.d.ts +171 -0
  300. package/dist/wire/consume.d.ts +26 -0
  301. package/dist/wire/encode.d.ts +221 -0
  302. package/dist/wire/files.d.ts +116 -0
  303. package/dist/wire/formats/anthropic.d.ts +2 -0
  304. package/dist/wire/formats/openai.d.ts +5 -0
  305. package/dist/wire/index.d.ts +16 -0
  306. package/dist/wire/media-types.d.ts +106 -0
  307. package/dist/wire/read.d.ts +26 -0
  308. package/dist/wire/sink-helpers.d.ts +21 -0
  309. package/dist/wire/sse.d.ts +33 -0
  310. package/dist/wire.d.ts +5 -53
  311. package/dist/wire.js +1126 -0
  312. package/frameworks/react/index.tsx +191 -158
  313. package/frameworks/react/runtime.tsx +21 -1
  314. package/frameworks/react/use-kai-chat.tsx +11 -1
  315. package/llms-full.txt +774 -151
  316. package/llms.txt +57 -5
  317. package/package.json +62 -8
  318. package/src/agent-tooling/archetypes.ts +127 -0
  319. package/src/agent-tooling/integrations/anthropic.ts +436 -0
  320. package/src/agent-tooling/integrations/cloudflare.ts +141 -52
  321. package/src/agent-tooling/integrations/langgraph.ts +80 -13
  322. package/src/agent-tooling/integrations/mastra.ts +161 -12
  323. package/src/agent-tooling/integrations/mock.ts +47 -8
  324. package/src/agent-tooling/integrations/ollama.ts +68 -24
  325. package/src/agent-tooling/integrations/openai.ts +89 -0
  326. package/src/agent-tooling/integrations/openrouter.ts +58 -8
  327. package/src/agent-tooling/integrations/pi.ts +104 -23
  328. package/src/agent-tooling/integrations/pydantic-ai.ts +61 -5
  329. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +120 -13
  330. package/src/agent-tooling/mcp/manifest.ts +206 -25
  331. package/src/agent-tooling/mcp/tools/debug.ts +13 -7
  332. package/src/agent-tooling/mcp/tools/reference.ts +285 -6
  333. package/src/agent-tooling/mcp/tools/scaffold.ts +4152 -661
  334. package/src/agent-tooling/registry.ts +74 -0
  335. package/src/agent-tooling/types.ts +361 -1
  336. package/src/components/artifact-card.tsx +120 -0
  337. package/src/components/audio-visualizer/index.tsx +9 -0
  338. package/src/components/audio-visualizer/labs/lab-choreography.ts +187 -0
  339. package/src/components/audio-visualizer/labs/lab-shaders.ts +363 -0
  340. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +102 -0
  341. package/src/components/audio-visualizer/shader-canvas.tsx +31 -1
  342. package/src/components/card-fallback.tsx +42 -10
  343. package/src/components/card-renderer.tsx +146 -9
  344. package/src/components/chat-container.tsx +4 -0
  345. package/src/components/chat-thread.tsx +128 -52
  346. package/src/components/choice-card.tsx +17 -29
  347. package/src/components/composer.tsx +12 -2
  348. package/src/components/confirm-card.tsx +24 -20
  349. package/src/components/context.tsx +30 -16
  350. package/src/components/conversation-item.tsx +6 -0
  351. package/src/components/conversation-list.tsx +18 -2
  352. package/src/components/file-tree.tsx +11 -22
  353. package/src/components/file-upload.tsx +14 -8
  354. package/src/components/form.tsx +14 -47
  355. package/src/components/loader.tsx +39 -12
  356. package/src/components/message-skills.tsx +4 -0
  357. package/src/components/message.tsx +294 -46
  358. package/src/components/model-switcher.tsx +38 -8
  359. package/src/components/reasoning.tsx +92 -5
  360. package/src/components/response-compare-types.ts +25 -0
  361. package/src/components/response-compare.tsx +4 -9
  362. package/src/components/source.tsx +50 -24
  363. package/src/components/tasks-card.tsx +10 -33
  364. package/src/components/thread.tsx +84 -42
  365. package/src/components/toast.tsx +17 -6
  366. package/src/components/tool-classify.ts +26 -0
  367. package/src/components/tool-types.ts +31 -1
  368. package/src/elements/agent-card.tsx +11 -11
  369. package/src/elements/artifact.tsx +15 -7
  370. package/src/elements/attachments.tsx +6 -4
  371. package/src/elements/avatar.tsx +1 -1
  372. package/src/elements/button.tsx +29 -6
  373. package/src/elements/card.tsx +2 -2
  374. package/src/elements/cards.tsx +109 -14
  375. package/src/elements/chain-of-thought.tsx +14 -10
  376. package/src/elements/chat-scope-picker.tsx +9 -7
  377. package/src/elements/chat-types.ts +59 -6
  378. package/src/elements/chat-workspace.tsx +50 -9
  379. package/src/elements/chat.tsx +90 -3
  380. package/src/elements/choice.tsx +8 -8
  381. package/src/elements/coachmark.tsx +1 -1
  382. package/src/elements/command.tsx +8 -23
  383. package/src/elements/compare.tsx +7 -6
  384. package/src/elements/compiled.css +1 -1
  385. package/src/elements/composer.tsx +8 -8
  386. package/src/elements/confirm-card.tsx +9 -9
  387. package/src/elements/context-meter.tsx +4 -18
  388. package/src/elements/conversation-list.tsx +14 -9
  389. package/src/elements/default-input.tsx +131 -8
  390. package/src/elements/define.tsx +178 -43
  391. package/src/elements/editable-label.tsx +17 -2
  392. package/src/elements/element-data-types.ts +112 -0
  393. package/src/elements/element-meta.json +1624 -306
  394. package/src/elements/element-types.d.ts +2645 -214
  395. package/src/elements/feedback-bar.tsx +1 -1
  396. package/src/elements/file-tree.tsx +1 -1
  397. package/src/elements/file-upload.tsx +1 -1
  398. package/src/elements/form.tsx +14 -6
  399. package/src/elements/input.tsx +1 -1
  400. package/src/elements/kbd.tsx +1 -1
  401. package/src/elements/menu.tsx +40 -32
  402. package/src/elements/message-skills.tsx +7 -9
  403. package/src/elements/message.tsx +200 -32
  404. package/src/elements/model-switcher.tsx +5 -3
  405. package/src/elements/pane.tsx +1 -1
  406. package/src/elements/prompt-dock.tsx +8 -8
  407. package/src/elements/prompt-input.tsx +10 -10
  408. package/src/elements/prompt-suggestions.tsx +7 -4
  409. package/src/elements/reasoning.tsx +1 -1
  410. package/src/elements/register.ts +9 -0
  411. package/src/elements/resizable.globals.d.ts +36 -0
  412. package/src/elements/resizable.tsx +24 -13
  413. package/src/elements/response-stream.tsx +1 -1
  414. package/src/elements/scroll-button.tsx +1 -1
  415. package/src/elements/search.tsx +6 -1
  416. package/src/elements/segmented.tsx +5 -11
  417. package/src/elements/separator.tsx +1 -1
  418. package/src/elements/slot-text.ts +73 -0
  419. package/src/elements/slots.ts +67 -24
  420. package/src/elements/source.tsx +21 -22
  421. package/src/elements/switch.tsx +3 -3
  422. package/src/elements/tasks.tsx +5 -4
  423. package/src/elements/thread.tsx +36 -4
  424. package/src/elements/toast.tsx +3 -2
  425. package/src/elements/tool.tsx +1 -1
  426. package/src/elements/validate-messages.ts +76 -0
  427. package/src/elements/voice-input.tsx +7 -7
  428. package/src/elements/voice-output.tsx +4 -4
  429. package/src/index.ts +145 -6
  430. package/src/primitives/card-component-types.ts +63 -0
  431. package/src/primitives/card-data-types.ts +312 -0
  432. package/src/primitives/card-recovery.ts +13 -2
  433. package/src/primitives/card-registry.tsx +34 -23
  434. package/src/primitives/card-schemas/artifact.schema.json +92 -0
  435. package/src/primitives/card-schemas/embed.schema.json +0 -2
  436. package/src/primitives/card-schemas/link.schema.json +0 -2
  437. package/src/primitives/card-tags.ts +61 -0
  438. package/src/primitives/card-validate-cards.ts +255 -0
  439. package/src/primitives/card-validate-generator.testlib.ts +38 -0
  440. package/src/primitives/card-validate-schemas.ts +58 -0
  441. package/src/primitives/card-validate.ts +48 -20
  442. package/src/primitives/create-tween.ts +54 -2
  443. package/src/primitives/message-feedback.ts +3 -2
  444. package/src/primitives/use-audio-analysis.ts +20 -1
  445. package/src/primitives/use-sequencer.ts +20 -1
  446. package/src/schemas/from-tool-call.ts +151 -0
  447. package/src/schemas/index.ts +340 -0
  448. package/src/schemas/provider-subsets.ts +538 -0
  449. package/src/schemas/registry.ts +355 -0
  450. package/src/schemas/tool-defs.ts +492 -0
  451. package/src/solid.ts +150 -0
  452. package/src/state/index.ts +27 -1
  453. package/src/state/messages.ts +21 -4
  454. package/src/state/mock.ts +211 -0
  455. package/src/state/parts.ts +295 -0
  456. package/src/state/stream.ts +56 -58
  457. package/src/ui/collapsible.tsx +17 -5
  458. package/src/ui/dropdown.tsx +46 -12
  459. package/src/ui/overlay.tsx +10 -4
  460. package/src/wire/chunk.ts +201 -0
  461. package/src/wire/consume.ts +440 -0
  462. package/src/wire/encode.ts +689 -0
  463. package/src/wire/files.ts +342 -0
  464. package/src/wire/formats/anthropic.ts +267 -0
  465. package/src/wire/formats/openai.ts +187 -0
  466. package/src/wire/index.ts +73 -0
  467. package/src/wire/media-types.ts +344 -0
  468. package/src/wire/read.ts +152 -0
  469. package/src/wire/sink-helpers.ts +50 -0
  470. package/src/wire/sse.ts +140 -0
  471. package/dist/create-tween-hvpmSuwW.js +0 -7
  472. package/dist/elements/chunks/arrow-left-DQocUFvy.js +0 -1
  473. package/dist/elements/chunks/audio-visualizer-BqNy7dfm.js +0 -1
  474. package/dist/elements/chunks/card-BkHbp4BA.js +0 -1
  475. package/dist/elements/chunks/chat-thread-CkRN6pZ7.js +0 -1
  476. package/dist/elements/chunks/check-B9-gn6SS.js +0 -1
  477. package/dist/elements/chunks/chevron-down-BNsxc2hk.js +0 -1
  478. package/dist/elements/chunks/chevron-right-Hv00StBO.js +0 -1
  479. package/dist/elements/chunks/circle-0e3KJTDr.js +0 -1
  480. package/dist/elements/chunks/circle-check-BNAS0JEy.js +0 -1
  481. package/dist/elements/chunks/code-block-BFUHn6Va.js +0 -1
  482. package/dist/elements/chunks/context-Cb7k4F-v.js +0 -1
  483. package/dist/elements/chunks/conversation-list-CvoAkWhN.js +0 -1
  484. package/dist/elements/chunks/create-tween-oVvAIG8r.js +0 -7
  485. package/dist/elements/chunks/default-input-Cqqilg9t.js +0 -1
  486. package/dist/elements/chunks/define-D1din7Ld.js +0 -1
  487. package/dist/elements/chunks/hover-card-Cmm6Q53m.js +0 -1
  488. package/dist/elements/chunks/message-BqyXDN3-.js +0 -1
  489. package/dist/elements/chunks/message-feedback-Djr3z6Yb.js +0 -1
  490. package/dist/elements/chunks/message-square-vFAgbDaX.js +0 -1
  491. package/dist/elements/chunks/model-switcher-B94YAKsM.js +0 -1
  492. package/dist/elements/chunks/reasoning-DTpCGtnY.js +0 -1
  493. package/dist/elements/chunks/scroll-button-B0cH5fXf.js +0 -1
  494. package/dist/elements/chunks/skeleton-DSXW5Yya.js +0 -1
  495. package/dist/elements/chunks/slots--V19HwUb.js +0 -1
  496. package/dist/elements/chunks/textarea-CUwqAX0G.js +0 -1
  497. package/dist/elements/chunks/tooltip-CgBZCVKp.js +0 -1
  498. package/dist/elements/chunks/use-card-resolution-BSu_XHjH.js +0 -1
  499. package/dist/elements/chunks/x-GRUeeQFT.js +0 -1
  500. package/dist/host-embed.d.ts +0 -33
  501. package/dist/kai-provider.d.ts +0 -2
  502. package/dist/origin.d.ts +0 -5
  503. package/dist/provider-runtime.d.ts +0 -27
  504. package/dist/register-impl-DQyejdfb.js +0 -145
  505. package/dist/validate.d.ts +0 -4
  506. package/dist/version.d.ts +0 -4
  507. package/src/components/component-meta.json +0 -4550
  508. package/src/elements/card-media.jpg +0 -0
  509. package/src/elements/resizable.d.ts +0 -27
  510. package/src/elements/video-poster.jpg +0 -0
@@ -6,16 +6,19 @@ type Item = string | { label: string; value?: string; icon?: string };
6
6
 
7
7
  interface Props extends Record<string, unknown> {
8
8
  /** The suggestions. Strings, or `{ label, value }` when the displayed text
9
- * and the emitted value differ. Set as a JS property. */
10
- suggestions: Item[];
9
+ * and the emitted value differ. Set as a JS property. Omit to supply them as
10
+ * `<kai-suggestion>` light-DOM children instead; when both are present the
11
+ * property's suggestions come first. */
12
+ suggestions?: Item[];
11
13
  /** Chip style: `'outline'` (default), `'ghost'`, or `'default'` (filled). */
12
14
  variant?: 'outline' | 'ghost' | 'default';
13
15
  /** Row height for `layout="list"`: `'md'` (default) or `'lg'` for taller rows.
14
16
  * Chips are unaffected. */
15
17
  size?: 'md' | 'lg';
16
18
  /** Layout: `'chips'` (default) renders a wrapping row of rounded pills;
17
- * `'list'` renders a vertical, full-width "Ideas for you" list each row
18
- * is left-aligned with a leading `icon`, a label, and a hover background. */
19
+ * `'list'` renders a vertical, full-width "Ideas for you" list where each
20
+ * row is left-aligned with a leading `icon`, a label, and a hover
21
+ * background. */
19
22
  layout?: 'chips' | 'list';
20
23
  /** Full-width left-aligned rows instead of pills. */
21
24
  block?: boolean;
@@ -18,7 +18,7 @@ interface Props extends Record<string, unknown> {
18
18
  streaming?: boolean;
19
19
  /** Render `text` as markdown. */
20
20
  markdown?: boolean;
21
- /** Gate the disclosure trigger programmatic `show()/hide()/toggle()` still
21
+ /** Gate the disclosure trigger: programmatic `show()/hide()/toggle()` still
22
22
  * work, but the trigger click no longer toggles. */
23
23
  disabled?: boolean;
24
24
  }
@@ -29,6 +29,15 @@ export type { ChatMessage, ChatMessageAction } from './chat-types';
29
29
  export { configureCodeHighlighting, isCodeHighlightingEnabled } from '../primitives/highlighter';
30
30
  export type { CodeHighlightingOptions } from '../primitives/highlighter';
31
31
 
32
+ // ToolPart.kind's doc comment in the shipped dist/elements.d.ts says "Derive with
33
+ // `classifyTool(type)`", but the function was exported from NO public entry, so a
34
+ // consumer following our own docs hit an unresolvable import. Total, deterministic
35
+ // and always terminating in 'generic' — safe to expose, and needed by anyone
36
+ // rendering tool calls themselves. tool-classify.ts imports nothing, so this stays
37
+ // SSR-safe and adds no weight to the register-all bundle.
38
+ export { classifyTool } from '../components/tool-classify';
39
+ export type { ToolKind } from '../components/tool-classify';
40
+
32
41
  // Imperative toast API — usable directly from the elements entry so consumers
33
42
  // who only import the web-components bundle still get `toast()`. The store is
34
43
  // SSR-safe (no DOM touched until the first toast is raised on the client).
@@ -0,0 +1,36 @@
1
+ // src/elements/resizable.globals.d.ts
2
+ // Hand-authored ambient types for the cross-element maximize PROTOCOL — the two
3
+ // raw composed CustomEvents `<kai-artifact>` and `<kai-resizable>`/`<kai-resizable-item>`
4
+ // exchange. The generated element-types.d.ts emits no HTMLElementEventMap entries,
5
+ // so without this `el.addEventListener('kai-maximize-intent', e => e.detail)` is
6
+ // TS2339 on `Event`. NOT regenerated by `npm run build`.
7
+ //
8
+ // THE FILENAME IS LOAD-BEARING and must not go back to `resizable.d.ts`.
9
+ // TypeScript drops a .d.ts when a same-named .ts/.tsx sits beside it, and
10
+ // `resizable.tsx` does. Under the old name this whole file was in NO tsc
11
+ // program, so every augmentation below was inert. Measured on the same probe,
12
+ // `el.addEventListener('kai-maximize-intent', e => e.detail)`:
13
+ // resizable.d.ts TS2339: Property 'detail' does not exist on 'Event'
14
+ // resizable.globals.d.ts clean -- narrowed to CustomEvent<KaiMaximizeIntentDetail>
15
+ //
16
+ // This file used to ALSO declare a global `KaiResizableElement` carrying
17
+ // `maximize`/`restore` plus an HTMLElementTagNameMap entry pointing at it. That
18
+ // half never worked: element-types.d.ts declares its own module-scoped
19
+ // `KaiResizableElement` and maps the tag to THAT, so the two entries collided
20
+ // (TS2717, invisible under the `skipLibCheck: true` every pass sets) and the
21
+ // generated one won — `document.querySelector('kai-resizable').maximize(0)` stayed
22
+ // TS2339. The methods now come from the GENERATOR (resizable.tsx routes them
23
+ // through `ctx.expose`, gen-element-types.mjs emits them onto the element
24
+ // interface), so the duplicate is gone and there is exactly one declaration of
25
+ // each name. Do not reintroduce it: a hand-written interface cannot win against
26
+ // the generated one, and generated files are regenerated.
27
+ import type { KaiMaximizeIntentDetail, KaiMaximizeStateDetail } from './resizable';
28
+
29
+ declare global {
30
+ interface HTMLElementEventMap {
31
+ 'kai-maximize-intent': CustomEvent<KaiMaximizeIntentDetail>;
32
+ 'kai-maximize-state': CustomEvent<KaiMaximizeStateDetail>;
33
+ }
34
+ }
35
+
36
+ export {};
@@ -57,9 +57,9 @@ interface GroupProps extends Record<string, unknown> {
57
57
  maximizedIndex?: number | null;
58
58
  /**
59
59
  * Divider affordance drawn inside each draggable handle's 8px grab zone:
60
- * - `line` (default) a 1px hairline, transparent at rest, tinting on hover/drag.
61
- * - `grip` a dotted grip handle.
62
- * - `none` no visible divider, just the invisible hit-area.
60
+ * - `line` (default): a 1px hairline, transparent at rest, tinting on hover/drag.
61
+ * - `grip`: a dotted grip handle.
62
+ * - `none`: no visible divider, just the invisible hit-area.
63
63
  * The full grab zone and keyboard/ARIA behavior are identical for all three.
64
64
  */
65
65
  handle?: 'line' | 'grip' | 'none';
@@ -70,6 +70,11 @@ interface GroupEvents extends Record<string, unknown> {
70
70
  'kai-change': { sizes: number[] };
71
71
  /** Observe layout maximize state. */
72
72
  'kai-maximize-change': { maximized: boolean; index: number | null };
73
+ /** Authoritative maximize state, dispatched as a raw composed CustomEvent (not
74
+ * through `dispatch`) onto the affected `<kai-resizable-item>` and, on restore,
75
+ * onto the group host. A nested element (e.g. `<kai-artifact>`) listens for it
76
+ * to reconcile its own toggle. */
77
+ 'kai-maximize-state': { maximized: boolean };
73
78
  }
74
79
 
75
80
  /**
@@ -84,7 +89,7 @@ defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
84
89
  orientation: 'horizontal',
85
90
  maximizedIndex: null,
86
91
  handle: 'line',
87
- }, (props, { element, dispatch }) => {
92
+ }, (props, { element, dispatch, expose }) => {
88
93
  const [items, setItems] = createSignal<ItemInfo[]>([]);
89
94
  const orientation = (): Orientation => (props.orientation === 'vertical' ? 'vertical' : 'horizontal');
90
95
 
@@ -405,13 +410,19 @@ defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
405
410
 
406
411
  // --- Task 3: imperative host methods + declarative maximizedIndex prop ---
407
412
 
408
- // Imperative host API (assigned onto the element; typed by resizable.d.ts).
409
- const host = element as unknown as { maximize(i: number): void; restore(): void };
410
- host.maximize = (i: number) => {
411
- const it = items()[i]?.el;
412
- if (it) maximizeItem(it);
413
- };
414
- host.restore = () => restore();
413
+ // Imperative host API. Routed through `expose()` like every other element's,
414
+ // so gen-element-api.mjs sees it and the generated element interface carries
415
+ // `maximize`/`restore` a direct assignment onto `element` was invisible to
416
+ // the extractor and needed an `as unknown as` cast to type-check here.
417
+ expose({
418
+ /** Imperatively maximize the item at `index` (thin wrapper over `maximizedIndex`). */
419
+ maximize: (index: number) => {
420
+ const it = items()[index]?.el;
421
+ if (it) maximizeItem(it);
422
+ },
423
+ /** Imperatively restore from the maximized layout. */
424
+ restore: () => restore(),
425
+ });
415
426
 
416
427
  // Declarative maximizedIndex → maximize/restore. Skip the initial null run.
417
428
  createEffect(
@@ -599,8 +610,8 @@ interface ItemProps extends Record<string, unknown> {
599
610
  /** Hide this panel; its divider is dropped and the rest reflow. */
600
611
  hidden?: boolean;
601
612
  /**
602
- * Collapse this panel same layout effect as `hidden` (divider dropped, the
603
- * rest reflow), but it WORKS as a bare boolean from framework JSX. A plain
613
+ * Collapse this panel. Same layout effect as `hidden` (divider dropped, the rest
614
+ * reflow), but it WORKS as a bare boolean from framework JSX. A plain
604
615
  * `<kai-resizable-item collapsed>` in React/Solid/Vue/Svelte collapses the panel
605
616
  * at the first render; `hidden` does not, because a JSX boolean sets neither the
606
617
  * `hidden` attribute nor the IDL property on a custom element, so the parent never
@@ -3,7 +3,7 @@ import { ResponseStream, type Mode } from '../components/response-stream';
3
3
 
4
4
  interface Props extends Record<string, unknown> {
5
5
  /** Text to stream. A string, or an `AsyncIterable<string>` (set as a JS
6
- * property async iterables can't be HTML attributes). */
6
+ * property, since async iterables can't be HTML attributes). */
7
7
  text?: string | AsyncIterable<string>;
8
8
  /** Reveal animation. */
9
9
  mode?: Mode;
@@ -19,7 +19,7 @@ interface Props extends Record<string, unknown> {
19
19
  /** Events fired by `<kai-scroll-button>`. */
20
20
  interface Events {
21
21
  /** Emitted when the user clicks the button and `scrollToBottom()` is
22
- * called. Carries no detail consumers use it to know a manual scroll
22
+ * called. Carries no detail; consumers use it to know a manual scroll
23
23
  * occurred. */
24
24
  'kai-scroll': void;
25
25
  }
@@ -6,7 +6,7 @@ import { Loader } from '../components/loader';
6
6
  import { renderIcon } from '../ui/icon';
7
7
 
8
8
  interface Props extends Record<string, unknown> {
9
- /** Controlled query settable and reflected to the `value` attribute. Read
9
+ /** Controlled query. Settable and reflected to the `value` attribute. Read
10
10
  * `el.value` for live state. */
11
11
  value?: string;
12
12
  /** Placeholder. Defaults to `Search…`. */
@@ -123,7 +123,12 @@ defineWebComponent<Props, Events>('kai-search', {
123
123
  };
124
124
 
125
125
  expose({
126
+ /** Focus the search input inside the shadow root. A native `focus()` on the
127
+ * host lands on the host itself and never reaches it. */
126
128
  focus: () => getInput()?.focus(),
129
+ /** Empty the field and fire `kai-search` with an empty value immediately,
130
+ * cancelling any debounced search still in flight, then return focus to the
131
+ * input. Same path as the trailing clear button. */
127
132
  clear,
128
133
  });
129
134
 
@@ -2,20 +2,14 @@ import { createEffect, createSignal, untrack } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
3
  import { Segmented, type SegmentedOption } from '../ui/segmented';
4
4
  import { renderIcon } from '../ui/icon';
5
-
6
- /** A single segment. `icon` is an icon-NAME string (web-component-friendly)
7
- * a curated name (e.g. `"code"`), a URL/data-URI, or plain text — resolved to a
8
- * glyph via the kit's icon renderer (the same path `kai-button`'s `icon` uses). */
9
- interface Option {
10
- value: string;
11
- label: string;
12
- icon?: string;
13
- }
5
+ // Public shape of the `options` prop; lives in ./element-data-types so the ROOT
6
+ // entry can re-export it (see that file's header).
7
+ import type { KaiSegmentedOption } from './element-data-types';
14
8
 
15
9
  interface Props extends Record<string, unknown> {
16
10
  /** The selectable segments, left to right. Set as a JS property (array). */
17
- options: Option[];
18
- /** Controlled selected `value` settable and reflected to the `value`
11
+ options: KaiSegmentedOption[];
12
+ /** Controlled selected `value`. Settable and reflected to the `value`
19
13
  * attribute. `el.value = 'preview'` drives it; choosing a segment updates it
20
14
  * and fires `kai-change`. Read `el.value` for live state. */
21
15
  value?: string;
@@ -3,7 +3,7 @@ import { defineWebComponent } from './define';
3
3
 
4
4
  interface Props extends Record<string, unknown> {
5
5
  /** `horizontal` (default, block + full-width) or `vertical` (a rule inside a
6
- * flex/grid row it stretches to the row height). */
6
+ * flex/grid row, stretching to the row height). */
7
7
  orientation?: 'horizontal' | 'vertical';
8
8
  }
9
9
 
@@ -0,0 +1,73 @@
1
+ import { createSignal, type Accessor } from 'solid-js';
2
+
3
+ /**
4
+ * Track whether a `<slot>` is projecting VISIBLE TEXT, so a facade can tell
5
+ * "this control shows its own name" from "this control is icon-only and needs
6
+ * one".
7
+ *
8
+ * WHY IT EXISTS. Slotted light-DOM text is part of the flattened tree, so it
9
+ * names the shadow `<button>` all by itself — measured, not assumed:
10
+ * `scripts/probe-button-accessible-name.mjs` reads chromium's AX tree and
11
+ * `<kai-button>Save</kai-button>` computes the name "Save" from `contents`,
12
+ * with no `aria-label` anywhere. An `aria-label` on top of that does not add a
13
+ * name, it REPLACES one, and a replacement that disagrees with the visible text
14
+ * is a WCAG 2.5.3 (Label in Name) failure: speech-input users say what they
15
+ * see, so a button reading "Save" whose accessible name is "Submit" cannot be
16
+ * activated by voice at all. `kai-checkpoint` already resolved this the same
17
+ * way; this is the reusable form of that decision.
18
+ *
19
+ * WHY A SIGNAL AND NOT A ONE-OFF READ. The facade renders while the HTML parser
20
+ * is still inside the element's own tag, so the light DOM is usually EMPTY at
21
+ * that moment and any synchronous read of `element.childNodes` reports "no text"
22
+ * for the most common case there is. `slotchange` is the event that tells the
23
+ * truth, and it fires on the initial assignment too.
24
+ *
25
+ * The initial value is therefore `false`, meaning "assume icon-only", which
26
+ * makes the pre-`slotchange` frame emit the `aria-label`. That direction is
27
+ * deliberate: an overridden name is a defect, an ABSENT name is a worse one, so
28
+ * the transient state is the named one. `slotchange` is queued as a mutation
29
+ * observer microtask, so it lands before paint and no assistive technology
30
+ * observes the transient.
31
+ */
32
+ export function createSlotText(options: {
33
+ /**
34
+ * Follow `assignedNodes({ flatten: true })`, which descends into nested
35
+ * light-DOM `<slot>` elements (a consumer wrapping the element in their OWN
36
+ * component and forwarding a slot) — and, when nothing is assigned, returns
37
+ * the slot's FALLBACK content.
38
+ *
39
+ * Only safe on a slot whose fallback is exactly the visible label. Do NOT set
40
+ * it on a slot whose fallback can render a non-name (an icon that happens to
41
+ * be plain text, say): the fallback would count as visible text and suppress
42
+ * the very `aria-label` that names the control. `kai-button`'s default slot
43
+ * has no fallback at all, so flatten there only buys the nested case;
44
+ * `kai-menu`'s trigger slot falls back to an icon, so it must not use it.
45
+ */
46
+ flatten?: boolean;
47
+ } = {}): {
48
+ /** Whether the slot is currently showing text. */
49
+ hasText: Accessor<boolean>;
50
+ /** `ref` for the `<slot>`. Re-reads on every `slotchange`. */
51
+ ref: (slot: HTMLSlotElement) => void;
52
+ } {
53
+ const [hasText, setHasText] = createSignal(false);
54
+
55
+ const read = (slot: HTMLSlotElement) => {
56
+ const nodes = slot.assignedNodes({ flatten: options.flatten ?? false });
57
+ setHasText(nodes.some((node) => (node.textContent ?? '').trim() !== ''));
58
+ };
59
+
60
+ return {
61
+ hasText,
62
+ ref: (slot: HTMLSlotElement) => {
63
+ // A slot outside a shadow root assigns nothing, and this ref runs before
64
+ // solid inserts it — so this first read is normally `false` and the
65
+ // slotchange below is what carries the answer. It is here for the case
66
+ // where the element is created with its children already in place
67
+ // (`el.textContent = 'Save'` then appended), where no assignment CHANGE
68
+ // happens after insertion and slotchange may never fire.
69
+ read(slot);
70
+ slot.addEventListener('slotchange', () => read(slot));
71
+ },
72
+ };
73
+ }
@@ -27,7 +27,7 @@ export const CHAT_SLOTS: SlotDef[] = [
27
27
  { name: 'header-end', mode: 'inject', doc: 'Trailing header controls.' },
28
28
  { name: 'header', mode: 'replace', part: true, doc: 'Full custom header; replaces the built-in title/model/context bar.' },
29
29
  { name: 'sidebar', mode: 'inject', part: true, doc: 'Left column (your nav / conversation list). Fixed width; use compose-your-own for resizable.' },
30
- { name: 'empty', mode: 'replace', doc: 'Custom zero-state rendered in the message area while the thread is empty. Replaces the empty message list only the composer and any suggestions still render.' },
30
+ { name: 'empty', mode: 'replace', doc: 'Custom zero-state rendered in the message area while the thread is empty. Replaces the empty message list only; the composer and any suggestions still render.' },
31
31
  { name: 'composer', mode: 'replace', doc: 'Full custom composer; you own submit + loading, drive the thread via messages.' },
32
32
  { name: 'composer-actions', mode: 'inject', doc: 'Accessory row above the composer.' },
33
33
  { name: 'footer', mode: 'inject', part: true, doc: 'Row below the composer (disclaimers, token meter).' },
@@ -42,8 +42,8 @@ export const CHAT_SLOTS: SlotDef[] = [
42
42
  * no outer block slot here. (When the input is nested inside `<kai-chat>`'s shadow,
43
43
  * that surrounding hole belongs to `kai-chat` — see `composer-actions`/`footer`.) */
44
44
  export const PROMPT_INPUT_SLOTS: SlotDef[] = [
45
- { name: 'input-top', mode: 'inject', doc: 'Inside the card, above the textarea (e.g. an inline status strip). For content above/below the whole card, use your own layout that is light DOM you control.' },
46
- { name: 'toolbar-start', mode: 'inject', doc: 'Leading controls in the input toolbar where a + menu goes.' },
45
+ { name: 'input-top', mode: 'inject', doc: 'Inside the card, above the textarea (e.g. an inline status strip). For content above/below the whole card, use your own layout; that is light DOM you control.' },
46
+ { name: 'toolbar-start', mode: 'inject', doc: 'Leading controls in the input toolbar, where a + menu goes.' },
47
47
  { name: 'toolbar-end', mode: 'inject', doc: 'Trailing controls in the toolbar, before the Send button.' },
48
48
  ];
49
49
 
@@ -52,7 +52,7 @@ export const PROMPT_INPUT_SLOTS: SlotDef[] = [
52
52
  export const CONVERSATIONS_SLOTS: SlotDef[] = [
53
53
  { name: 'header', mode: 'replace', doc: 'Full custom title bar; replaces the built-in toggle / "Chats" / New-chat row.' },
54
54
  { name: 'empty', mode: 'replace', doc: 'Custom zero-state shown when there are no conversations; replaces the built-in "No conversations yet".' },
55
- { name: 'footer', mode: 'inject', doc: 'A row below the list account, settings, or usage.' },
55
+ { name: 'footer', mode: 'inject', doc: 'A row below the list: account, settings, or usage.' },
56
56
  ];
57
57
 
58
58
  /** Styleable `::part`s of `<kai-conversations>`. */
@@ -69,15 +69,15 @@ export const CONVERSATIONS_PARTS: PartDef[] = [
69
69
  * REPLACES the built-in avatar rail (pair it with `avatar="none"` to omit the
70
70
  * rail entirely). These are the keystone of compose-your-own message lists. */
71
71
  export const MESSAGE_SLOTS: SlotDef[] = [
72
- { name: 'before-body', mode: 'inject', doc: 'A per-message header at the TOP of the body, above reasoning/tools/content a model-name label, a role + timestamp line.' },
73
- { name: 'after-body', mode: 'inject', doc: 'A row at the BOTTOM of the body, below the action bar a citation/sources row, a token-cost/latency line.' },
72
+ { name: 'before-body', mode: 'inject', doc: 'A per-message header at the TOP of the body, above reasoning/tools/content: a model-name label, a role + timestamp line.' },
73
+ { name: 'after-body', mode: 'inject', doc: 'A row at the BOTTOM of the body, below the action bar: a citation/sources row, a token-cost/latency line.' },
74
74
  { name: 'avatar', mode: 'replace', part: true, 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.' },
75
75
  ];
76
76
 
77
77
  /** Slots of `<kai-notice>`. The message is the default slot; these are the named seams. */
78
78
  export const NOTICE_SLOTS: SlotDef[] = [
79
- { name: 'action', mode: 'inject', doc: 'A trailing action beside the message a link or button.' },
80
- { name: 'icon', mode: 'replace', doc: 'A custom leading icon (any inline SVG, inherits `currentColor`). Overrides the severity default and the `icon` prop the same escape hatch as `kai-button`.' },
79
+ { name: 'action', mode: 'inject', doc: 'A trailing action beside the message: a link or button.' },
80
+ { name: 'icon', mode: 'replace', doc: 'A custom leading icon (any inline SVG, inherits `currentColor`). Overrides the severity default and the `icon` prop, the same escape hatch as `kai-button`.' },
81
81
  ];
82
82
 
83
83
  /** Slots of `<kai-button>` (the label is the default slot). */
@@ -124,7 +124,7 @@ export const CHAT_PARTS: PartDef[] = [
124
124
  export const PROMPT_INPUT_PARTS: PartDef[] = [
125
125
  {
126
126
  name: 'send',
127
- doc: 'The send button. Restyle from outside, or hide it entirely (Enter-only) hiding is pure CSS, which is why there is no `submit="never"`.',
127
+ doc: 'The send button. Restyle from outside, or hide it entirely (Enter-only). Hiding is pure CSS, which is why there is no `submit="never"`.',
128
128
  recipe: 'kai-prompt-input::part(send) { display: none } /* Enter-only; or restyle: background, border-radius, … */',
129
129
  },
130
130
  ];
@@ -206,13 +206,18 @@ export const MESSAGE_PARTS: PartDef[] = [
206
206
  doc: 'The action-bar row (copy / like / regenerate …). Restyle its spacing or hide it entirely from outside.',
207
207
  recipe: 'kai-message::part(actions) { gap: 0.25rem }',
208
208
  },
209
+ {
210
+ name: 'citations',
211
+ 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.',
212
+ recipe: 'kai-message::part(citations) { gap: 0.5rem }',
213
+ },
209
214
  ];
210
215
 
211
216
  /** Styleable `::part`s of `<kai-attachments>`. */
212
217
  export const ATTACHMENTS_PARTS: PartDef[] = [
213
218
  {
214
219
  name: 'preview',
215
- 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.',
220
+ 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.',
216
221
  recipe: 'kai-attachments::part(preview) { max-width: 32rem; max-height: 24rem }',
217
222
  },
218
223
  ];
@@ -395,6 +400,15 @@ export const PROGRESS_BAR_PARTS: PartDef[] = [
395
400
  { name: 'fill', doc: 'The filled portion; its width follows value/max. Recolor it from outside.', recipe: 'kai-progress-bar::part(fill) { background: var(--color-tool-green) }' },
396
401
  ];
397
402
 
403
+ /** Styleable `::part`s of `<kai-context>`. The usage meter is the same shared
404
+ * ProgressBar `<kai-progress-bar>` renders, mounted inside this element's own
405
+ * shadow root, so `kai-context` exposes the same two names. Both sit inside the
406
+ * hover-card breakdown and are in the DOM only while that card is open. */
407
+ export const CONTEXT_PARTS: PartDef[] = [
408
+ { name: 'track', doc: 'The usage meter track inside the hover-card breakdown. Carries `role="progressbar"` and is in the DOM only while the card is open. Restyle its height, radius, or background from outside.', recipe: 'kai-context::part(track) { height: 0.5rem }' },
409
+ { name: 'fill', doc: 'The used-tokens portion of that meter. Its width follows `usedTokens / maxTokens`; its default color is the severity hue picked by `warnThreshold` / `dangerThreshold`, so recoloring it from outside replaces that signal.', recipe: 'kai-context::part(fill) { background: var(--color-tool-blue) }' },
410
+ ];
411
+
398
412
  /** Styleable `::part`s of `<kai-file-tree>` — the changed-files / diff bits, shown
399
413
  * only when a file carries diff metadata (or the `summary` attribute is set). */
400
414
  export const FILE_TREE_PARTS: PartDef[] = [
@@ -434,6 +448,17 @@ export const FILE_TREE_PARTS: PartDef[] = [
434
448
  export interface ElementComposition {
435
449
  slots?: SlotDef[];
436
450
  parts?: PartDef[];
451
+ /**
452
+ * What the element's DEFAULT (unnamed) `<slot>` projects — i.e. what a consumer
453
+ * puts between the tags. Kept OUT of `slots` on purpose: those arrays are also
454
+ * read at runtime by `readSlots()`, which would query a meaningless `[slot=""]`.
455
+ * scripts/gen-element-api.mjs merges it back in as a slot with the empty name,
456
+ * which is how the Custom Elements Manifest spells the default slot.
457
+ *
458
+ * Every facade that renders a bare `<slot />` needs one; guarded by
459
+ * tests/elements/slot-registry-coverage.test.ts.
460
+ */
461
+ children?: string;
437
462
  }
438
463
 
439
464
  /** Slots + styleable `::part`s of `<kai-prompt-dock>`. */
@@ -558,6 +583,17 @@ export const THREAD_SLOTS: SlotDef[] = [
558
583
  { name: 'empty', mode: 'replace', doc: 'Custom zero-state rendered in the message area while the thread is empty; replaces the built-in default.' },
559
584
  ];
560
585
 
586
+ /** Slots of `<kai-empty>`. The body is the default slot; `media` is the named seam. */
587
+ export const EMPTY_SLOTS: SlotDef[] = [
588
+ { name: 'media', mode: 'replace', doc: 'The leading illustration or icon above the title (any inline SVG or <img>). Replaces the built-in media box.' },
589
+ ];
590
+
591
+ /** Slots of `<kai-popover>`. The panel body is the default slot; `trigger` is the
592
+ * control the panel anchors to and opens from. */
593
+ export const POPOVER_SLOTS: SlotDef[] = [
594
+ { name: 'trigger', mode: 'replace', doc: 'The control that opens the popover (a button, an avatar, …). The panel anchors to it.' },
595
+ ];
596
+
561
597
  /** Styleable `::part`s of `<kai-audio-visualizer>`. Every DOM variant (`bar`,
562
598
  * `grid`, `radial`) shares the `bar`/`cell` markup pattern; the shader variants
563
599
  * (`wave`, `aurora`) share the `canvas` part. Lit items ALSO carry the
@@ -599,38 +635,45 @@ export const ELEMENT_COMPOSITION: Record<string, ElementComposition> = {
599
635
  'kai-message': { slots: MESSAGE_SLOTS, parts: MESSAGE_PARTS },
600
636
  'kai-thread': { slots: THREAD_SLOTS },
601
637
  'kai-prompt-input': { slots: PROMPT_INPUT_SLOTS, parts: PROMPT_INPUT_PARTS },
602
- 'kai-button': { slots: BUTTON_SLOTS, parts: BUTTON_PARTS },
603
- 'kai-badge': { parts: BADGE_PARTS },
638
+ 'kai-button': { slots: BUTTON_SLOTS, parts: BUTTON_PARTS, children: 'The button\'s label. Omit it for an icon-only button (pair with `aria-label`).' },
639
+ 'kai-badge': { parts: BADGE_PARTS, children: 'The badge\'s label: text, or a small inline icon plus text.' },
604
640
  'kai-icon': { parts: ICON_PARTS },
605
641
  'kai-separator': { parts: SEPARATOR_PARTS },
606
- 'kai-scroll-area': { parts: SCROLL_AREA_PARTS },
607
- 'kai-notice': { slots: NOTICE_SLOTS },
608
- 'kai-hover-card': { slots: HOVER_CARD_SLOTS },
642
+ 'kai-scroll-area': { parts: SCROLL_AREA_PARTS, children: 'The scrollable content.' },
643
+ 'kai-notice': { slots: NOTICE_SLOTS, children: 'The notice message. `icon` and `action` are the named seams around it.' },
644
+ 'kai-hover-card': { slots: HOVER_CARD_SLOTS, children: 'The TRIGGER the card hovers off. The card body is the `card` slot.' },
609
645
  'kai-menu': { slots: MENU_SLOTS, parts: MENU_PARTS },
610
646
  'kai-skeleton': { parts: SKELETON_PARTS },
611
647
  'kai-attachments': { parts: ATTACHMENTS_PARTS },
612
648
  'kai-status': { parts: STATUS_PARTS },
613
649
  'kai-tabs': { parts: TABS_PARTS },
614
650
  'kai-voice-output': { parts: VOICE_OUTPUT_PARTS },
615
- 'kai-screen': { slots: SCREEN_SLOTS, parts: SCREEN_PARTS },
616
- 'kai-card': { slots: CARD_SLOTS, parts: CARD_PARTS },
651
+ 'kai-screen': { slots: SCREEN_SLOTS, parts: SCREEN_PARTS, children: 'The screen body, below the title bar.' },
652
+ 'kai-card': { slots: CARD_SLOTS, parts: CARD_PARTS, children: 'The card body, below the header/media regions.' },
617
653
  'kai-workspace': { slots: WORKSPACE_SLOTS, parts: WORKSPACE_PARTS },
618
654
  'kai-nav': { parts: NAV_PARTS },
619
- 'kai-coachmark': { slots: COACHMARK_SLOTS, parts: COACHMARK_PARTS },
655
+ 'kai-coachmark': { slots: COACHMARK_SLOTS, parts: COACHMARK_PARTS, children: 'The ANCHOR the coachmark points at: the element it attaches to and positions against. The bubble body is the `content` slot.' },
620
656
  'kai-progress-bar': { parts: PROGRESS_BAR_PARTS },
657
+ 'kai-context': { parts: CONTEXT_PARTS },
621
658
  'kai-file-tree': { parts: FILE_TREE_PARTS },
622
- 'kai-prompt-dock': { slots: PROMPT_DOCK_SLOTS, parts: PROMPT_DOCK_PARTS },
659
+ 'kai-prompt-dock': { slots: PROMPT_DOCK_SLOTS, parts: PROMPT_DOCK_PARTS, children: 'The input the dock wraps, typically a `<kai-prompt-input>`. The `top`/`bottom` slots are the lips around it.' },
623
660
  'kai-segmented': { parts: SEGMENTED_PARTS },
624
- 'kai-settings-group': { parts: SETTINGS_GROUP_PARTS },
661
+ 'kai-settings-group': { parts: SETTINGS_GROUP_PARTS, children: 'The `<kai-setting-item>` rows in this group.' },
625
662
  'kai-setting-item': { slots: SETTING_ITEM_SLOTS, parts: SETTING_ITEM_PARTS },
626
- 'kai-pane': { slots: PANE_SLOTS, parts: PANE_PARTS },
627
- 'kai-pane-group': { parts: PANE_GROUP_PARTS },
663
+ 'kai-pane': { slots: PANE_SLOTS, parts: PANE_PARTS, children: 'The pane body, below the header row.' },
664
+ 'kai-pane-group': { parts: PANE_GROUP_PARTS, children: 'Content shown for every tab. Use it INSTEAD of the per-tab `slot="<tab id>"` seams when you swap the content yourself.' },
628
665
  'kai-agent-card': { parts: AGENT_CARD_PARTS },
629
- 'kai-dialog': { slots: DIALOG_SLOTS, parts: DIALOG_PARTS },
666
+ 'kai-dialog': { slots: DIALOG_SLOTS, parts: DIALOG_PARTS, children: 'The dialog body, between the `header` and `footer` slots.' },
630
667
  'kai-input': { slots: INPUT_SLOTS, parts: INPUT_PARTS },
631
668
  'kai-search': { parts: SEARCH_PARTS },
632
- 'kai-kbd': { parts: KBD_PARTS },
669
+ 'kai-kbd': { parts: KBD_PARTS, children: 'Literal key text, when you are not using the `keys` prop to render key caps.' },
633
670
  'kai-editable-label': { parts: EDITABLE_LABEL_PARTS },
671
+ 'kai-empty': { slots: EMPTY_SLOTS, children: 'The empty-state body below the title/description, usually the call to action.' },
672
+ 'kai-file-upload': { children: 'Custom dropzone content, replacing the default label (the `label` prop is the fallback).' },
673
+ 'kai-popover': { slots: POPOVER_SLOTS, children: 'The popover panel body. The control that opens it is the `trigger` slot.' },
674
+ 'kai-resizable': { children: 'The `<kai-resizable-item>` panels, in order. Dividers are inserted between them.' },
675
+ 'kai-resizable-item': { children: 'This panel\'s content.' },
676
+ 'kai-tooltip': { children: 'The TRIGGER the tooltip describes. The tip text is the `text` prop.' },
634
677
  'kai-audio-visualizer': { parts: AUDIO_VISUALIZER_PARTS },
635
678
  };
636
679
 
@@ -1,6 +1,9 @@
1
1
  import { createSignal, For, onCleanup, onMount, Show } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
3
  import { Source, SourceTrigger, SourceContent, SourceList } from '../components/source';
4
+ // Public shape of the `sources` prop; lives in ./element-data-types so the ROOT
5
+ // entry can re-export it (see that file's header).
6
+ import type { KaiSourceItem } from './element-data-types';
4
7
 
5
8
  // --- <kai-source> — a single citation link with hover preview ---
6
9
 
@@ -9,8 +12,9 @@ interface SourceProps extends Record<string, unknown> {
9
12
  href?: string;
10
13
  /** Trigger label (defaults to the domain). */
11
14
  label?: string;
12
- /** Hover-card headline. Attribute: `headline` (`title` is avoided it's a
13
- * global HTML attribute that reflects in a CE constructor and breaks it). */
15
+ /** Hover-card headline. Attribute: `headline` (`title` is avoided because it
16
+ * is a global HTML attribute that reflects in a CE constructor and breaks
17
+ * it). */
14
18
  headline?: string;
15
19
  /** Hover-card body text describing the source. */
16
20
  description?: string;
@@ -42,17 +46,12 @@ defineWebComponent<SourceProps>('kai-source', {
42
46
 
43
47
  // --- <kai-sources> — a wrapped list of citation links ---
44
48
 
45
- interface SourceItem {
46
- href: string;
47
- title?: string;
48
- description?: string;
49
- label?: string;
50
- showFavicon?: boolean;
51
- }
52
49
 
53
50
  interface SourceListProps extends Record<string, unknown> {
54
- /** The sources to render. Set as a JS property. */
55
- sources: SourceItem[];
51
+ /** The sources to render. Set as a JS property. Omit to supply them as
52
+ * `<kai-source>` light-DOM children instead; when both are present the
53
+ * property's sources come first. */
54
+ sources?: KaiSourceItem[];
56
55
  /** Show favicons on all items (per-item `showFavicon` overrides). */
57
56
  showFavicon?: boolean;
58
57
  /**
@@ -60,22 +59,22 @@ interface SourceListProps extends Record<string, unknown> {
60
59
  * merged (prop + declarative-children) list (`[1]`, `[2]`, …) instead of the
61
60
  * per-item `label` or domain fallback.
62
61
  *
63
- * HTML attribute: `numbered` (boolean bare attribute or `numbered="true"`).
64
- * JS property: `el.numbered = true`.
62
+ * HTML attribute: `numbered` (boolean: a bare attribute or
63
+ * `numbered="true"`). JS property: `el.numbered = true`.
65
64
  */
66
65
  numbered?: boolean;
67
66
  }
68
67
 
69
- /** Parse a single light-DOM `<kai-source>` element into a `SourceItem` descriptor.
68
+ /** Parse a single light-DOM `<kai-source>` element into a `KaiSourceItem` descriptor.
70
69
  * Attribute mapping:
71
- * - `href` → SourceItem.href
72
- * - `label` → SourceItem.label
73
- * - `headline` → SourceItem.title (matches kai-source's prop name; "title" is a
70
+ * - `href` → KaiSourceItem.href
71
+ * - `label` → KaiSourceItem.label
72
+ * - `headline` → KaiSourceItem.title (matches kai-source's prop name; "title" is a
74
73
  * reserved HTMLElement attribute so kai-source uses "headline")
75
- * - `description` → SourceItem.description
76
- * - `show-favicon`→ SourceItem.showFavicon (bare boolean attribute)
74
+ * - `description` → KaiSourceItem.description
75
+ * - `show-favicon`→ KaiSourceItem.showFavicon (bare boolean attribute)
77
76
  */
78
- export function parseKaiSourceElement(n: Element): SourceItem {
77
+ export function parseKaiSourceElement(n: Element): KaiSourceItem {
79
78
  return {
80
79
  href: n.getAttribute('href') ?? '',
81
80
  label: n.getAttribute('label') ?? undefined,
@@ -92,7 +91,7 @@ defineWebComponent<SourceListProps>('kai-sources', {
92
91
  }, (props, { element, flag }) => {
93
92
  // Read declarative <kai-source> children from light DOM.
94
93
  // The shadow root has no <slot> for them, so they are invisible — pure data carriers.
95
- const [slottedSources, setSlottedSources] = createSignal<SourceItem[]>([]);
94
+ const [slottedSources, setSlottedSources] = createSignal<KaiSourceItem[]>([]);
96
95
  onMount(() => {
97
96
  const read = () => {
98
97
  const nodes = [...element.querySelectorAll('kai-source')];
@@ -105,7 +104,7 @@ defineWebComponent<SourceListProps>('kai-sources', {
105
104
  });
106
105
 
107
106
  // Prop sources take precedence; slotted children are appended after.
108
- const allSources = () => [...props.sources, ...slottedSources()];
107
+ const allSources = () => [...(props.sources ?? []), ...slottedSources()];
109
108
 
110
109
  const isNumbered = () => flag('numbered');
111
110
 
@@ -3,9 +3,9 @@ import { defineWebComponent } from './define';
3
3
  import { Switch } from '../ui/switch';
4
4
 
5
5
  interface Props extends Record<string, unknown> {
6
- /** Controlled checked state settable and reflected to the `checked`
7
- * attribute. `el.checked = true` (or `<kai-switch checked>`) drives it; the
8
- * toggle UI updates it and fires `kai-change`. Read `el.checked` for live state. */
6
+ /** Controlled checked state. Settable and reflected to the `checked` attribute.
7
+ * `el.checked = true` (or `<kai-switch checked>`) drives it; the toggle UI updates
8
+ * it and fires `kai-change`. Read `el.checked` for live state. */
9
9
  checked?: boolean;
10
10
  /** Initial checked state on mount (uncontrolled seed). Bare attribute
11
11
  * (`<kai-switch default-checked>`) turns it on. */