@kitn.ai/ui 0.16.0 → 0.18.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 (493) hide show
  1. package/README.md +55 -17
  2. package/dist/components/artifact.d.ts +39 -1
  3. package/dist/components/attachment-types.d.ts +12 -0
  4. package/dist/components/attachments.d.ts +2 -10
  5. package/dist/components/card.d.ts +27 -0
  6. package/dist/components/chain-of-thought.d.ts +78 -2
  7. package/dist/components/chat-scope-picker.d.ts +7 -0
  8. package/dist/components/chat-thread.d.ts +39 -16
  9. package/dist/components/choice-card.d.ts +27 -0
  10. package/dist/components/coachmark.d.ts +49 -0
  11. package/dist/components/composer-dom.d.ts +35 -0
  12. package/dist/components/composer-highlight.d.ts +48 -0
  13. package/dist/components/composer-history.d.ts +34 -0
  14. package/dist/components/composer.d.ts +86 -0
  15. package/dist/components/confirm-card.d.ts +17 -0
  16. package/dist/components/conversation-item.d.ts +9 -0
  17. package/dist/components/conversation-list.d.ts +36 -1
  18. package/dist/components/dismissed-stub.d.ts +22 -0
  19. package/dist/components/file-tree.d.ts +15 -0
  20. package/dist/components/form.d.ts +34 -0
  21. package/dist/components/markdown.d.ts +3 -0
  22. package/dist/components/message.d.ts +71 -2
  23. package/dist/components/model-switcher.d.ts +7 -0
  24. package/dist/components/prompt-input.d.ts +13 -4
  25. package/dist/components/prompt-suggestion.d.ts +9 -1
  26. package/dist/components/reasoning.d.ts +14 -1
  27. package/dist/components/response-compare-types.d.ts +66 -0
  28. package/dist/components/response-compare.d.ts +65 -0
  29. package/dist/components/screen.d.ts +46 -0
  30. package/dist/components/tasks-card.d.ts +50 -1
  31. package/dist/components/toast.d.ts +58 -0
  32. package/dist/components/tool-types.d.ts +10 -0
  33. package/dist/components/tool.d.ts +8 -8
  34. package/dist/components/use-card-resolution.d.ts +10 -6
  35. package/dist/components/voice-input.d.ts +27 -0
  36. package/dist/components/voice-output.d.ts +33 -0
  37. package/dist/core-C8fzo39E.js +12 -0
  38. package/dist/custom-elements.json +8472 -1691
  39. package/dist/elements/agent-card.d.ts +1 -0
  40. package/dist/elements/agent-card.js +1 -0
  41. package/dist/elements/artifact.js +1 -0
  42. package/dist/elements/attachments.js +1 -0
  43. package/dist/elements/autoloader.d.ts +2 -0
  44. package/dist/elements/autoloader.js +1 -0
  45. package/dist/elements/avatar.d.ts +1 -0
  46. package/dist/elements/avatar.js +1 -0
  47. package/dist/elements/badge.d.ts +1 -0
  48. package/dist/elements/badge.js +1 -0
  49. package/dist/elements/button.d.ts +1 -0
  50. package/dist/elements/button.js +1 -0
  51. package/dist/elements/card.js +1 -0
  52. package/dist/elements/cards.d.ts +1 -0
  53. package/dist/elements/cards.js +1 -0
  54. package/dist/elements/chain-of-thought.d.ts +0 -12
  55. package/dist/elements/chain-of-thought.js +1 -0
  56. package/dist/elements/chat-scope-picker.js +1 -0
  57. package/dist/elements/chat-types.d.ts +8 -2
  58. package/dist/elements/chat-workspace.js +1 -0
  59. package/dist/elements/chat.js +1 -0
  60. package/dist/elements/checkpoint.js +1 -0
  61. package/dist/elements/choice.js +1 -0
  62. package/dist/elements/chunks/Icon-DLLBeLG5.js +1 -0
  63. package/dist/elements/chunks/action-icons-UB4V5FNq.js +1 -0
  64. package/dist/elements/chunks/arrow-left-C-gwlUmx.js +1 -0
  65. package/dist/elements/chunks/attachments-CgbErf1r.js +1 -0
  66. package/dist/elements/chunks/badge-DTQpgB6N.js +1 -0
  67. package/dist/elements/chunks/bash-InADTalH.js +1 -0
  68. package/dist/elements/chunks/button-XDUM6lXs.js +1 -0
  69. package/dist/elements/chunks/card-CBlFZ-7I.js +1 -0
  70. package/dist/elements/chunks/card-routing-C986KuUA.js +1 -0
  71. package/dist/elements/chunks/chat-thread-BIhmqwNL.js +1 -0
  72. package/dist/elements/chunks/check-hGUoVIKb.js +1 -0
  73. package/dist/elements/chunks/chevron-down-DDoaSUtO.js +1 -0
  74. package/dist/elements/chunks/chevron-right-CdGEUakB.js +1 -0
  75. package/dist/elements/chunks/circle-BKAZdmzb.js +1 -0
  76. package/dist/elements/chunks/circle-check-CmYG-y3I.js +1 -0
  77. package/dist/elements/chunks/circle-x-DewgAEym.js +1 -0
  78. package/dist/elements/chunks/cn-CU7UAWzk.js +1 -0
  79. package/dist/elements/chunks/code-block-DedwxwFI.js +1 -0
  80. package/dist/elements/chunks/collapsible-FfgmTHtM.js +1 -0
  81. package/dist/elements/chunks/composer-Cfbw5HKT.js +65 -0
  82. package/dist/elements/chunks/context-DwJmxlRE.js +1 -0
  83. package/dist/elements/chunks/conversation-list-DsCQMfPq.js +1 -0
  84. package/dist/elements/chunks/core-AYMC6_lb.js +12 -0
  85. package/dist/elements/chunks/css-M7EaDHN_.js +1 -0
  86. package/dist/elements/chunks/default-input-BuqsoENC.js +1 -0
  87. package/dist/elements/chunks/define-rGsaWsLL.js +1 -0
  88. package/dist/elements/chunks/disclosure-CwoAkpMH.js +1 -0
  89. package/dist/elements/chunks/download-DJ06G3Bz.js +1 -0
  90. package/dist/elements/chunks/dropdown-BFg8ri_R.js +1 -0
  91. package/dist/elements/chunks/ellipsis-dlN6YvGw.js +1 -0
  92. package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +141 -0
  93. package/dist/elements/chunks/external-link-DBX2lc_R.js +1 -0
  94. package/dist/elements/chunks/file-text-HfwUx4F9.js +1 -0
  95. package/dist/elements/chunks/file-tree-C6Toj71u.js +1 -0
  96. package/dist/elements/chunks/folder-MYuqa9Xp.js +1 -0
  97. package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +1 -0
  98. package/dist/elements/chunks/github-light-JYsPkUQd.js +1 -0
  99. package/dist/elements/chunks/hover-card-gE7iyXdW.js +1 -0
  100. package/dist/elements/chunks/html-CPZ3oZQ7.js +1 -0
  101. package/dist/elements/chunks/icon-Vqz4ivrY.js +1 -0
  102. package/dist/elements/chunks/index-BCRhi84a.js +1 -0
  103. package/dist/elements/chunks/info-B_toFS0l.js +1 -0
  104. package/dist/elements/chunks/input-gzbHYZvQ.js +1 -0
  105. package/dist/elements/chunks/javascript-C25yR2R2.js +1 -0
  106. package/dist/elements/chunks/json-DxJze_jm.js +1 -0
  107. package/dist/elements/chunks/kbd-n49c4KZm.js +1 -0
  108. package/dist/elements/chunks/link-CKPs9yM0.js +1 -0
  109. package/dist/elements/chunks/loader-q6MamGus.js +1 -0
  110. package/dist/elements/chunks/markdown-DBrcqq4S.js +64 -0
  111. package/dist/elements/chunks/message-CTqaYI0s.js +1 -0
  112. package/dist/elements/chunks/message-feedback-Cvzm03w0.js +1 -0
  113. package/dist/elements/chunks/message-square-CUg9eRCi.js +1 -0
  114. package/dist/elements/chunks/minimize-2-l2klxP6K.js +1 -0
  115. package/dist/elements/chunks/model-switcher-CmyjiHO1.js +1 -0
  116. package/dist/elements/chunks/overlay-C8sOYqjT.js +1 -0
  117. package/dist/elements/chunks/paperclip-42Ia7xHD.js +1 -0
  118. package/dist/elements/chunks/progress-bar-tzKMWAwO.js +1 -0
  119. package/dist/elements/chunks/prompt-suggestion-D3F6vP_A.js +1 -0
  120. package/dist/elements/chunks/reasoning-BJNmmyov.js +1 -0
  121. package/dist/elements/chunks/resizable-BRsk19qI.js +1 -0
  122. package/dist/elements/chunks/rotate-cw-BgcggLHC.js +1 -0
  123. package/dist/elements/chunks/scroll-area-CgGbFFbT.js +1 -0
  124. package/dist/elements/chunks/separator-8hM4GdHE.js +1 -0
  125. package/dist/elements/chunks/settings-CaUIYOg-.js +1 -0
  126. package/dist/elements/chunks/settings-group-CYjOVIZQ.js +1 -0
  127. package/dist/elements/chunks/share-BTYM3Ddt.js +1 -0
  128. package/dist/elements/chunks/skeleton-DsTYrPUe.js +1 -0
  129. package/dist/elements/chunks/slots-DkZ-Cmha.js +1 -0
  130. package/dist/elements/chunks/star-9R3LBQ9n.js +1 -0
  131. package/dist/elements/chunks/store-CYl5Y0_u.js +1 -0
  132. package/dist/elements/chunks/svelte--5p79yCD.js +1 -0
  133. package/dist/elements/chunks/text-shimmer-CaYGv8Se.js +1 -0
  134. package/dist/elements/chunks/textarea-NEr2SLcD.js +1 -0
  135. package/dist/elements/chunks/thumbs-up-DZYZkFfc.js +1 -0
  136. package/dist/elements/chunks/toast-store-ClxVZRcc.js +1 -0
  137. package/dist/elements/chunks/tool-CHZOmoe9.js +1 -0
  138. package/dist/elements/chunks/tooltip-WpHElELC.js +1 -0
  139. package/dist/elements/chunks/triangle-alert-BlS80PUg.js +1 -0
  140. package/dist/elements/chunks/tsx-B8rCNbgL.js +1 -0
  141. package/dist/elements/chunks/typescript-RycA9KXf.js +1 -0
  142. package/dist/elements/chunks/use-card-resolution-VSVoxDeJ.js +1 -0
  143. package/dist/elements/chunks/video-DxTPZqT8.js +1 -0
  144. package/dist/elements/chunks/vue-BmIZj4XD.js +1 -0
  145. package/dist/elements/chunks/x-C1qtndxn.js +1 -0
  146. package/dist/elements/coachmark.d.ts +1 -0
  147. package/dist/elements/coachmark.js +1 -0
  148. package/dist/elements/code-block.js +1 -0
  149. package/dist/elements/command.d.ts +1 -0
  150. package/dist/elements/command.js +1 -0
  151. package/dist/elements/compare.d.ts +1 -0
  152. package/dist/elements/compare.js +1 -0
  153. package/dist/elements/composer.d.ts +1 -0
  154. package/dist/elements/composer.js +1 -0
  155. package/dist/elements/confirm-card.js +1 -0
  156. package/dist/elements/context-meter.js +1 -0
  157. package/dist/elements/conversation-list.d.ts +1 -11
  158. package/dist/elements/conversation-list.js +1 -0
  159. package/dist/elements/default-input.d.ts +20 -9
  160. package/dist/elements/define.d.ts +11 -0
  161. package/dist/elements/dialog.d.ts +1 -0
  162. package/dist/elements/dialog.js +1 -0
  163. package/dist/elements/disclosure.d.ts +37 -0
  164. package/dist/elements/editable-label.d.ts +1 -0
  165. package/dist/elements/editable-label.js +1 -0
  166. package/dist/elements/embed.js +1 -0
  167. package/dist/elements/empty.js +1 -0
  168. package/dist/elements/feedback-bar.js +1 -0
  169. package/dist/elements/file-tree.js +1 -0
  170. package/dist/elements/file-upload.js +1 -0
  171. package/dist/elements/form.js +1 -0
  172. package/dist/elements/hover-card.d.ts +1 -0
  173. package/dist/elements/hover-card.js +1 -0
  174. package/dist/elements/icon.d.ts +1 -0
  175. package/dist/elements/icon.js +1 -0
  176. package/dist/elements/image.js +1 -0
  177. package/dist/elements/input.d.ts +1 -0
  178. package/dist/elements/input.js +1 -0
  179. package/dist/elements/kbd.d.ts +1 -0
  180. package/dist/elements/kbd.js +1 -0
  181. package/dist/elements/link-preview.js +1 -0
  182. package/dist/elements/loader.js +1 -0
  183. package/dist/elements/markdown.js +1 -0
  184. package/dist/elements/menu.d.ts +1 -0
  185. package/dist/elements/menu.js +1 -0
  186. package/dist/elements/message-skills.d.ts +0 -16
  187. package/dist/elements/message-skills.js +1 -0
  188. package/dist/elements/message.js +1 -0
  189. package/dist/elements/model-switcher.d.ts +1 -11
  190. package/dist/elements/model-switcher.js +1 -0
  191. package/dist/elements/nav.d.ts +1 -0
  192. package/dist/elements/nav.js +1 -0
  193. package/dist/elements/notice.d.ts +1 -0
  194. package/dist/elements/notice.js +1 -0
  195. package/dist/elements/pane-group.d.ts +1 -0
  196. package/dist/elements/pane-group.js +1 -0
  197. package/dist/elements/pane.d.ts +1 -0
  198. package/dist/elements/pane.js +1 -0
  199. package/dist/elements/popover.js +1 -0
  200. package/dist/elements/progress-bar.d.ts +1 -0
  201. package/dist/elements/progress-bar.js +1 -0
  202. package/dist/elements/prompt-dock.d.ts +1 -0
  203. package/dist/elements/prompt-dock.js +1 -0
  204. package/dist/elements/prompt-input.d.ts +1 -9
  205. package/dist/elements/prompt-input.js +1 -0
  206. package/dist/elements/prompt-suggestions.d.ts +0 -6
  207. package/dist/elements/prompt-suggestions.js +1 -0
  208. package/dist/elements/reasoning.js +1 -0
  209. package/dist/elements/register.d.ts +10 -0
  210. package/dist/elements/remote.js +1 -0
  211. package/dist/elements/resizable.d.ts +1 -17
  212. package/dist/elements/resizable.js +1 -0
  213. package/dist/elements/response-stream.js +14 -0
  214. package/dist/elements/screen.d.ts +1 -0
  215. package/dist/elements/screen.js +1 -0
  216. package/dist/elements/scroll-area.d.ts +1 -0
  217. package/dist/elements/scroll-area.js +1 -0
  218. package/dist/elements/scroll-button.js +1 -0
  219. package/dist/elements/search.d.ts +1 -0
  220. package/dist/elements/search.js +1 -0
  221. package/dist/elements/segmented.d.ts +1 -0
  222. package/dist/elements/segmented.js +1 -0
  223. package/dist/elements/separator.d.ts +1 -0
  224. package/dist/elements/separator.js +1 -0
  225. package/dist/elements/setting-item.d.ts +1 -0
  226. package/dist/elements/setting-item.js +1 -0
  227. package/dist/elements/settings-group.d.ts +1 -0
  228. package/dist/elements/settings-group.js +1 -0
  229. package/dist/elements/skeleton.d.ts +1 -0
  230. package/dist/elements/skeleton.js +1 -0
  231. package/dist/elements/slots.d.ts +176 -0
  232. package/dist/elements/source.d.ts +0 -17
  233. package/dist/elements/source.js +1 -0
  234. package/dist/elements/status.d.ts +1 -0
  235. package/dist/elements/status.js +1 -0
  236. package/dist/elements/switch.js +1 -0
  237. package/dist/elements/tabs.d.ts +1 -0
  238. package/dist/elements/tabs.js +1 -0
  239. package/dist/elements/tasks.js +1 -0
  240. package/dist/elements/text-shimmer.js +1 -0
  241. package/dist/elements/thinking-bar.js +1 -0
  242. package/dist/elements/toast.d.ts +1 -0
  243. package/dist/elements/toast.js +1 -0
  244. package/dist/elements/tool.js +1 -0
  245. package/dist/elements/tooltip.d.ts +1 -0
  246. package/dist/elements/tooltip.js +1 -0
  247. package/dist/elements/voice-input.js +1 -0
  248. package/dist/elements/voice-output.d.ts +1 -0
  249. package/dist/elements/voice-output.js +1 -0
  250. package/dist/elements.d.ts +772 -61
  251. package/dist/engine-javascript-C1x7zo1_.js +141 -0
  252. package/dist/index.d.ts +15 -2
  253. package/dist/index.js +14405 -9810
  254. package/dist/kai.es.js +1 -0
  255. package/dist/llms/llms-full.txt +1234 -107
  256. package/dist/llms/llms.txt +4 -4
  257. package/dist/mcp.es.js +217 -6
  258. package/dist/primitives/card-contract.d.ts +20 -4
  259. package/dist/primitives/card-recovery.d.ts +55 -0
  260. package/dist/primitives/composer-model.d.ts +22 -0
  261. package/dist/primitives/composer-triggers.d.ts +19 -0
  262. package/dist/primitives/create-kai-chat.d.ts +38 -0
  263. package/dist/primitives/message-feedback.d.ts +35 -0
  264. package/dist/primitives/toast-store.d.ts +118 -0
  265. package/dist/primitives/use-speech-recognition.d.ts +26 -0
  266. package/dist/react/index.d.ts +1166 -98
  267. package/dist/react/runtime.d.ts +9 -2
  268. package/dist/react/use-kai-chat.d.ts +41 -0
  269. package/dist/react.js +575 -186
  270. package/dist/register-impl-CYWGkgbI.js +141 -0
  271. package/dist/schemas/choice.schema.json +5 -0
  272. package/dist/schemas/tasks.schema.json +7 -2
  273. package/dist/state/index.d.ts +4 -0
  274. package/dist/state/messages.d.ts +11 -0
  275. package/dist/state/stream.d.ts +22 -0
  276. package/dist/state/suggestions.d.ts +4 -0
  277. package/dist/state.js +117 -0
  278. package/dist/theme.tokens.css +87 -0
  279. package/dist/types.d.ts +4 -0
  280. package/dist/ui/agent-card.d.ts +61 -0
  281. package/dist/ui/button.d.ts +5 -2
  282. package/dist/ui/card.d.ts +61 -0
  283. package/dist/ui/collapsible.d.ts +15 -1
  284. package/dist/ui/command.d.ts +33 -0
  285. package/dist/ui/dialog.d.ts +42 -0
  286. package/dist/ui/dropdown.d.ts +95 -1
  287. package/dist/ui/editable-label.d.ts +26 -0
  288. package/dist/ui/hover-card.d.ts +13 -1
  289. package/dist/ui/icon.d.ts +18 -0
  290. package/dist/ui/input.d.ts +33 -0
  291. package/dist/ui/kbd.d.ts +21 -0
  292. package/dist/ui/nav.d.ts +62 -0
  293. package/dist/ui/notice.d.ts +31 -0
  294. package/dist/ui/overlay.d.ts +12 -0
  295. package/dist/ui/pane-grid.d.ts +58 -0
  296. package/dist/ui/pane-group.d.ts +75 -0
  297. package/dist/ui/pane.d.ts +78 -0
  298. package/dist/ui/popover.d.ts +11 -1
  299. package/dist/ui/progress-bar.d.ts +23 -0
  300. package/dist/ui/prompt-dock.d.ts +96 -0
  301. package/dist/ui/resizable.d.ts +12 -0
  302. package/dist/ui/scroll-area.d.ts +4 -0
  303. package/dist/ui/segmented.d.ts +28 -0
  304. package/dist/ui/settings-group.d.ts +32 -0
  305. package/dist/ui/skeleton.d.ts +12 -0
  306. package/dist/ui/stat.d.ts +16 -0
  307. package/dist/ui/status.d.ts +13 -0
  308. package/dist/ui/switch.d.ts +8 -1
  309. package/dist/ui/tabs.d.ts +35 -0
  310. package/dist/ui/tooltip.d.ts +20 -1
  311. package/frameworks/react/index.tsx +1100 -163
  312. package/frameworks/react/runtime.tsx +30 -1
  313. package/frameworks/react/use-kai-chat.tsx +87 -0
  314. package/llms-full.txt +1234 -107
  315. package/llms.txt +4 -4
  316. package/package.json +36 -12
  317. package/src/agent-tooling/mcp/manifest.ts +14 -0
  318. package/src/agent-tooling/mcp/tools/debug.ts +194 -6
  319. package/src/agent-tooling/mcp/tools/reference.ts +32 -0
  320. package/src/agent-tooling/mcp/tools/scaffold.ts +162 -1
  321. package/src/components/artifact.tsx +98 -13
  322. package/src/components/attachment-types.ts +13 -0
  323. package/src/components/attachments.tsx +4 -14
  324. package/src/components/card.tsx +109 -15
  325. package/src/components/chain-of-thought.tsx +210 -1
  326. package/src/components/chat-scope-picker.tsx +13 -3
  327. package/src/components/chat-thread.tsx +238 -137
  328. package/src/components/choice-card.tsx +136 -15
  329. package/src/components/coachmark.tsx +245 -0
  330. package/src/components/component-meta.json +921 -108
  331. package/src/components/composer-dom.ts +159 -0
  332. package/src/components/composer-highlight.ts +242 -0
  333. package/src/components/composer-history.ts +82 -0
  334. package/src/components/composer.tsx +979 -0
  335. package/src/components/confirm-card.tsx +69 -2
  336. package/src/components/conversation-item.tsx +69 -7
  337. package/src/components/conversation-list.tsx +134 -37
  338. package/src/components/dismissed-stub.tsx +80 -0
  339. package/src/components/file-tree.tsx +197 -47
  340. package/src/components/form-widgets.tsx +9 -7
  341. package/src/components/form.tsx +161 -20
  342. package/src/components/image.tsx +3 -5
  343. package/src/components/link-preview.tsx +5 -4
  344. package/src/components/markdown.tsx +5 -2
  345. package/src/components/message.tsx +174 -14
  346. package/src/components/model-switcher.tsx +19 -4
  347. package/src/components/prompt-input.tsx +46 -75
  348. package/src/components/prompt-suggestion.tsx +48 -16
  349. package/src/components/reasoning.tsx +29 -6
  350. package/src/components/response-compare-types.ts +127 -0
  351. package/src/components/response-compare.tsx +460 -0
  352. package/src/components/screen.tsx +176 -0
  353. package/src/components/tasks-card.tsx +374 -23
  354. package/src/components/toast.tsx +486 -0
  355. package/src/components/tool-types.ts +10 -0
  356. package/src/components/tool.tsx +22 -16
  357. package/src/components/use-card-resolution.ts +24 -8
  358. package/src/components/voice-input.tsx +102 -19
  359. package/src/components/voice-output.tsx +202 -0
  360. package/src/elements/agent-card.tsx +67 -0
  361. package/src/elements/artifact.tsx +53 -4
  362. package/src/elements/attachments.tsx +1 -0
  363. package/src/elements/autoloader.ts +89 -0
  364. package/src/elements/avatar.tsx +33 -0
  365. package/src/elements/badge.tsx +32 -0
  366. package/src/elements/button.tsx +126 -0
  367. package/src/elements/card-media.jpg +0 -0
  368. package/src/elements/card.tsx +124 -31
  369. package/src/elements/cards.tsx +81 -7
  370. package/src/elements/chain-of-thought.tsx +77 -32
  371. package/src/elements/chat-scope-picker.tsx +35 -8
  372. package/src/elements/chat-types.ts +9 -2
  373. package/src/elements/chat-workspace.tsx +157 -43
  374. package/src/elements/chat.tsx +49 -25
  375. package/src/elements/choice.tsx +71 -19
  376. package/src/elements/coachmark.tsx +90 -0
  377. package/src/elements/command.tsx +209 -0
  378. package/src/elements/compare.tsx +110 -0
  379. package/src/elements/compiled.css +1 -1
  380. package/src/elements/composer.tsx +151 -0
  381. package/src/elements/confirm-card.tsx +36 -11
  382. package/src/elements/conversation-list.tsx +80 -11
  383. package/src/elements/default-input.tsx +75 -53
  384. package/src/elements/define.tsx +47 -6
  385. package/src/elements/dialog.tsx +98 -0
  386. package/src/elements/disclosure.ts +73 -0
  387. package/src/elements/editable-label.tsx +125 -0
  388. package/src/elements/element-manifest.json +310 -0
  389. package/src/elements/element-meta.json +5954 -1605
  390. package/src/elements/element-types.d.ts +771 -60
  391. package/src/elements/file-tree.tsx +12 -2
  392. package/src/elements/file-upload.tsx +1 -1
  393. package/src/elements/form.tsx +54 -11
  394. package/src/elements/hover-card.tsx +80 -0
  395. package/src/elements/icon-names.json +48 -0
  396. package/src/elements/icon.tsx +41 -0
  397. package/src/elements/input.tsx +203 -0
  398. package/src/elements/kbd.tsx +45 -0
  399. package/src/elements/menu.tsx +217 -0
  400. package/src/elements/message.tsx +84 -55
  401. package/src/elements/model-switcher.tsx +27 -1
  402. package/src/elements/nav.tsx +87 -0
  403. package/src/elements/notice.tsx +53 -0
  404. package/src/elements/pane-group.tsx +119 -0
  405. package/src/elements/pane.tsx +129 -0
  406. package/src/elements/popover.tsx +39 -17
  407. package/src/elements/progress-bar.tsx +39 -0
  408. package/src/elements/prompt-dock.tsx +81 -0
  409. package/src/elements/prompt-input.tsx +112 -63
  410. package/src/elements/prompt-suggestions.tsx +25 -9
  411. package/src/elements/reasoning.tsx +30 -9
  412. package/src/elements/register-impl.ts +41 -3
  413. package/src/elements/register.ts +20 -3
  414. package/src/elements/remote.tsx +4 -0
  415. package/src/elements/resizable.tsx +48 -11
  416. package/src/elements/screen.tsx +90 -0
  417. package/src/elements/scroll-area.tsx +33 -0
  418. package/src/elements/search.tsx +180 -0
  419. package/src/elements/segmented.tsx +135 -0
  420. package/src/elements/separator.tsx +36 -0
  421. package/src/elements/setting-item.tsx +50 -0
  422. package/src/elements/settings-group.tsx +37 -0
  423. package/src/elements/skeleton.tsx +45 -0
  424. package/src/elements/slots.ts +607 -0
  425. package/src/elements/source.tsx +13 -6
  426. package/src/elements/status.tsx +42 -0
  427. package/src/elements/styles.css +19 -0
  428. package/src/elements/switch.tsx +89 -14
  429. package/src/elements/tabs.tsx +95 -0
  430. package/src/elements/tasks.tsx +70 -14
  431. package/src/elements/toast.tsx +89 -0
  432. package/src/elements/tool.tsx +43 -9
  433. package/src/elements/tooltip.tsx +85 -0
  434. package/src/elements/video-poster.jpg +0 -0
  435. package/src/elements/voice-input.tsx +66 -16
  436. package/src/elements/voice-output.tsx +69 -0
  437. package/src/index.ts +35 -2
  438. package/src/primitives/card-contract.ts +14 -5
  439. package/src/primitives/card-recovery.ts +149 -0
  440. package/src/primitives/card-routing.ts +3 -0
  441. package/src/primitives/card-schemas/choice.schema.json +5 -0
  442. package/src/primitives/card-schemas/tasks.schema.json +7 -2
  443. package/src/primitives/composer-model.ts +49 -0
  444. package/src/primitives/composer-triggers.ts +35 -0
  445. package/src/primitives/create-kai-chat.ts +66 -0
  446. package/src/primitives/message-feedback.ts +123 -0
  447. package/src/primitives/toast-store.ts +276 -0
  448. package/src/primitives/use-speech-recognition.ts +135 -0
  449. package/src/state/index.ts +6 -0
  450. package/src/state/messages.ts +36 -0
  451. package/src/state/stream.ts +92 -0
  452. package/src/state/suggestions.ts +9 -0
  453. package/src/types.ts +4 -0
  454. package/src/ui/agent-card.tsx +212 -0
  455. package/src/ui/button.tsx +16 -5
  456. package/src/ui/card.tsx +245 -0
  457. package/src/ui/collapsible.tsx +30 -4
  458. package/src/ui/command.tsx +99 -0
  459. package/src/ui/dialog.tsx +217 -0
  460. package/src/ui/dropdown.tsx +375 -13
  461. package/src/ui/editable-label.tsx +112 -0
  462. package/src/ui/hover-card.tsx +28 -5
  463. package/src/ui/icon.tsx +110 -0
  464. package/src/ui/input.tsx +132 -0
  465. package/src/ui/kbd.tsx +118 -0
  466. package/src/ui/nav.tsx +282 -0
  467. package/src/ui/notice.tsx +84 -0
  468. package/src/ui/overlay.tsx +108 -2
  469. package/src/ui/pane-grid.tsx +116 -0
  470. package/src/ui/pane-group.tsx +280 -0
  471. package/src/ui/pane.tsx +193 -0
  472. package/src/ui/popover.tsx +16 -2
  473. package/src/ui/progress-bar.tsx +83 -0
  474. package/src/ui/prompt-dock.tsx +145 -0
  475. package/src/ui/resizable.tsx +69 -1
  476. package/src/ui/scroll-area.tsx +14 -3
  477. package/src/ui/segmented.tsx +109 -0
  478. package/src/ui/settings-group.tsx +67 -0
  479. package/src/ui/skeleton.tsx +62 -5
  480. package/src/ui/stat.tsx +41 -0
  481. package/src/ui/status.tsx +48 -0
  482. package/src/ui/switch.tsx +49 -23
  483. package/src/ui/tabs.tsx +168 -0
  484. package/src/ui/tooltip.tsx +57 -7
  485. package/theme.css +113 -0
  486. package/dist/components/slash-command.d.ts +0 -15
  487. package/dist/kitn-chat.es.js +0 -1
  488. package/dist/register-impl-wCsFPoh9.js +0 -77
  489. package/dist/register-ujhr1nBS.js +0 -1
  490. package/src/components/slash-command.tsx +0 -232
  491. package/src/elements/framework-usage.json +0 -563
  492. /package/dist/{kitn-chat-provider.d.ts → kai-provider.d.ts} +0 -0
  493. /package/dist/{kitn-chat-provider.es.js → kai-provider.es.js} +0 -0
@@ -1,6 +1,6 @@
1
1
  import { createSignal, createEffect, on, onMount, onCleanup, For, Show, type JSX } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
- import { ResizableHandle, normalizeSize } from '../ui/resizable';
3
+ import { ResizableHandle, normalizeSize, clampBasis } from '../ui/resizable';
4
4
 
5
5
  type Orientation = 'horizontal' | 'vertical';
6
6
 
@@ -34,6 +34,7 @@ interface ItemInfo {
34
34
  max?: string;
35
35
  locked: boolean;
36
36
  hidden: boolean;
37
+ collapsed: boolean;
37
38
  }
38
39
 
39
40
  /** Max number of panels a single group lays out (nest for more). */
@@ -100,6 +101,13 @@ defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
100
101
  el.setAttribute('data-kai-default-size', el.getAttribute('size') ?? '');
101
102
  }
102
103
  const defaultSize = el.getAttribute('data-kai-default-size') || undefined;
104
+ // The `collapsed` boolean prop is reflected to a `collapsed` attribute by the
105
+ // item facade (see kai-resizable-item), so reading the attribute here works
106
+ // at INITIAL render from any framework — unlike the bare `hidden` boolean,
107
+ // whose JSX form sets neither the attribute nor the IDL property on a custom
108
+ // element. Treated as hidden-for-layout, independently of `hidden` so the
109
+ // back-compat hidden path (and maximize, which drives `hidden`) is untouched.
110
+ const collapsed = el.hasAttribute('collapsed') && el.getAttribute('collapsed') !== 'false';
103
111
  return {
104
112
  el,
105
113
  size: el.getAttribute('size') ?? undefined,
@@ -111,14 +119,15 @@ defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
111
119
  // (and direct `el.hidden = true`) set the property, which doesn't reflect
112
120
  // to the attribute on a custom element.
113
121
  hidden: el.hidden || (el.hasAttribute('hidden') && el.getAttribute('hidden') !== 'false'),
122
+ collapsed,
114
123
  };
115
124
  });
116
125
 
117
126
  // Assign each visible item to its panel slot by visible order; clear the
118
- // rest so hidden/extra items don't leak into a slot.
127
+ // rest so hidden/extra/collapsed items don't leak into a slot.
119
128
  let visIdx = 0;
120
129
  for (const info of parsed) {
121
- if (info.hidden) {
130
+ if (info.hidden || info.collapsed) {
122
131
  info.el.removeAttribute('slot');
123
132
  } else {
124
133
  info.el.setAttribute('slot', `p${visIdx}`);
@@ -153,12 +162,12 @@ defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
153
162
  const b = next[i];
154
163
  if (a.el !== b.el) return true;
155
164
  if (a.size !== b.size || a.min !== b.min || a.max !== b.max) return true;
156
- if (a.locked !== b.locked || a.hidden !== b.hidden) return true;
165
+ if (a.locked !== b.locked || a.hidden !== b.hidden || a.collapsed !== b.collapsed) return true;
157
166
  }
158
167
  return false;
159
168
  }
160
169
 
161
- const visible = () => items().filter((i) => !i.hidden);
170
+ const visible = () => items().filter((i) => !i.hidden && !i.collapsed);
162
171
 
163
172
  /** Compute current panel sizes (percent of container) from the rendered DOM. */
164
173
  function currentSizes(): number[] {
@@ -358,9 +367,11 @@ defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
358
367
  // maximized item is still present and visible.
359
368
  const maximizedEl = stash.item;
360
369
  const isConnected = maximizedEl.isConnected && element.contains(maximizedEl);
361
- const isVisible = isConnected && !(maximizedEl.hidden || maximizedEl.hasAttribute('hidden'));
370
+ const isVisible = isConnected
371
+ && !(maximizedEl.hidden || maximizedEl.hasAttribute('hidden'))
372
+ && !(maximizedEl.hasAttribute('collapsed') && maximizedEl.getAttribute('collapsed') !== 'false');
362
373
  if (!isConnected || !isVisible) {
363
- // The maximized item was removed or hidden out from under us → restore.
374
+ // The maximized item was removed or hidden/collapsed out from under us → restore.
364
375
  restore();
365
376
  return;
366
377
  }
@@ -375,7 +386,7 @@ defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
375
386
  // the host's own attributes.
376
387
  subtree: true,
377
388
  attributes: true,
378
- attributeFilter: ['size', 'locked', 'min', 'max', 'hidden'],
389
+ attributeFilter: ['size', 'locked', 'min', 'max', 'hidden', 'collapsed'],
379
390
  });
380
391
  onCleanup(() => {
381
392
  mo.disconnect();
@@ -432,7 +443,9 @@ defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
432
443
  const min = boundAttrs(info.min);
433
444
  const max = boundAttrs(info.max);
434
445
  const def = boundAttrs(info.defaultSize);
435
- const basis = normalizeSize(info.size);
446
+ // Clamp the INITIAL basis into [min, max] so a % size on a wide
447
+ // container never paints past a px max and then snaps on first drag.
448
+ const basis = clampBasis(normalizeSize(info.size), normalizeSize(info.min), normalizeSize(info.max));
436
449
  const prev = () => visible()[i() - 1];
437
450
  const isStatic = () => !!(info.locked || prev()?.locked);
438
451
  return (
@@ -514,6 +527,16 @@ interface ItemProps extends Record<string, unknown> {
514
527
  locked?: boolean;
515
528
  /** Hide this panel; its divider is dropped and the rest reflow. */
516
529
  hidden?: boolean;
530
+ /**
531
+ * Collapse this panel — same layout effect as `hidden` (divider dropped, the
532
+ * rest reflow), but it WORKS as a bare boolean from framework JSX. A plain
533
+ * `<kai-resizable-item collapsed>` in React/Solid/Vue/Svelte collapses the panel
534
+ * at the first render; `hidden` does not, because a JSX boolean sets neither the
535
+ * `hidden` attribute nor the IDL property on a custom element, so the parent never
536
+ * sees it. The facade reflects `collapsed` to a `collapsed` attribute the parent
537
+ * reads. Prefer this over `hidden` for declarative collapse.
538
+ */
539
+ collapsed?: boolean;
517
540
  }
518
541
 
519
542
  /**
@@ -527,7 +550,20 @@ defineWebComponent<ItemProps>('kai-resizable-item', {
527
550
  max: undefined,
528
551
  locked: false,
529
552
  hidden: false,
530
- }, () => (
553
+ collapsed: false,
554
+ }, (_props, { element, flag }) => {
555
+ // Reflect the reactive `collapsed` prop to the `collapsed` ATTRIBUTE the parent
556
+ // <kai-resizable> reads (and observes). This is what makes a bare JSX boolean
557
+ // collapse the panel at INITIAL render from any framework: component-register
558
+ // parses `<kai-resizable-item collapsed>` to `undefined` (not `true`), and a JSX
559
+ // boolean sets neither `hidden` nor the IDL property — so `flag('collapsed')`
560
+ // (which also honours the attribute) is the reliable source, and toggleAttribute
561
+ // mirrors it back so the parent's readItems()/MutationObserver lay it out. Same
562
+ // pattern as <kai-chat>'s `loading` reflection. We touch only `collapsed`, never
563
+ // `hidden`, so the back-compat hidden path and maximize (which drive `hidden`)
564
+ // are untouched.
565
+ createEffect(() => { element.toggleAttribute('collapsed', flag('collapsed')); });
566
+ return (
531
567
  <>
532
568
  {/* The item host fills the panel's single grid cell (the panel stretches it on
533
569
  both axes) and OWNS the scroll: `display:block; width/height:100%;
@@ -550,4 +586,5 @@ defineWebComponent<ItemProps>('kai-resizable-item', {
550
586
  <slot />
551
587
  </div>
552
588
  </>
553
- ) as unknown as JSX.Element);
589
+ ) as unknown as JSX.Element;
590
+ });
@@ -0,0 +1,90 @@
1
+ import { defineWebComponent } from './define';
2
+ import { Screen, type ScreenController } from '../components/screen';
3
+ import { wireDisclosure } from './disclosure';
4
+
5
+ interface Props extends Record<string, unknown> {
6
+ /** Drive/observe open state (Shoelace-style: settable + reflected to the `open`
7
+ * attribute; the element still self-manages). Set `el.open = true`, or
8
+ * `<kai-screen open>`; listen for `kai-open-change`. */
9
+ open?: boolean;
10
+ /** Initial open state on mount (uncontrolled seed). */
11
+ defaultOpen?: boolean;
12
+ /** Header title text. A projected `title` slot overrides it. (Named `headline`
13
+ * because `title` collides with the global `HTMLElement.title` attribute.) */
14
+ headline?: string;
15
+ /** Show the back button (default true). */
16
+ back?: boolean;
17
+ /** Opt out of marking sibling elements inert/aria-hidden while open (for unusual layouts). */
18
+ noInert?: boolean;
19
+ }
20
+
21
+ /** Events fired by `<kai-screen>`. */
22
+ interface Events {
23
+ /** Back navigation intent: the back button or Escape. The consumer flips their
24
+ * own routing in response (the screen knows nothing about the trigger). */
25
+ 'kai-back': Record<string, never>;
26
+ /** The screen opened or closed (a method, `Escape` close, or driven `open`). */
27
+ 'kai-open-change': { open: boolean };
28
+ }
29
+
30
+ /**
31
+ * `<kai-screen>` is a developer-swapped, full-bleed overlay destination: the
32
+ * push/drill-in surface that takes over its mount point under a back-header. The
33
+ * developer owns the swap (their own routing flips `open` in response to their
34
+ * trigger button and the screen's `kai-back`); the screen owns being the takeover.
35
+ *
36
+ * It fills whatever it is mounted in (mount at the app root for a full takeover,
37
+ * in a positioned region for a scoped one), marks sibling elements `inert` while
38
+ * open (the standard modal pattern; opt out with `no-inert`), moves focus in on
39
+ * open and restores it on close, and runs an enter/exit transition that honors
40
+ * `prefers-reduced-motion`. `Escape` fires `kai-back`.
41
+ *
42
+ * ```html
43
+ * <kai-screen headline="Design">
44
+ * <button slot="actions"><kai-avatar></kai-avatar></button>
45
+ * <div>…your surface…</div>
46
+ * </kai-screen>
47
+ * ```
48
+ *
49
+ * Open state is the standard disclosure surface: settable+reflecting `open`,
50
+ * `kai-open-change`, and `show()`/`hide()`/`toggle()`; seed with `default-open`.
51
+ * Parts: `header` · `back` · `title` · `body`.
52
+ */
53
+ defineWebComponent<Props, Events>('kai-screen', {
54
+ open: undefined,
55
+ defaultOpen: undefined,
56
+ headline: undefined,
57
+ back: undefined,
58
+ noInert: undefined,
59
+ }, (props, ctx) => {
60
+ const { flag, element, dispatch, expose } = ctx;
61
+ let api: ScreenController | undefined;
62
+ let surface: HTMLElement | undefined;
63
+
64
+ // The standard disclosure surface: settable+reflecting `open`, kai-open-change,
65
+ // show/hide/toggle. See ./disclosure. This is the SOLE emitter of kai-open-change.
66
+ wireDisclosure(ctx, () => api, () => props.open);
67
+
68
+ // focus() shadows the host's native focus so it targets the screen surface
69
+ // inside the shadow root (the WebAwesome/Shoelace convention).
70
+ expose({
71
+ /** Move focus to the screen surface (no-op while closed). */
72
+ focus: (options?: FocusOptions) => surface?.focus(options),
73
+ });
74
+
75
+ return (
76
+ <Screen
77
+ defaultOpen={flag('defaultOpen')}
78
+ back={!(props.back === false || element.getAttribute('back') === 'false')}
79
+ noInert={flag('noInert')}
80
+ host={() => element}
81
+ titleSlot={<slot name="title">{props.headline as string | undefined}</slot>}
82
+ actions={<slot name="actions" />}
83
+ onBack={() => { dispatch('kai-back', {}); }}
84
+ controllerRef={(a) => (api = a)}
85
+ surfaceRef={(el) => (surface = el)}
86
+ >
87
+ <slot />
88
+ </Screen>
89
+ );
90
+ });
@@ -0,0 +1,33 @@
1
+ import { ScrollArea, type ScrollOrientation } from '../ui/scroll-area';
2
+ import { defineWebComponent } from './define';
3
+
4
+ interface Props extends Record<string, unknown> {
5
+ /** Which axis scrolls. `vertical` (default) · `horizontal` · `both`. The cross
6
+ * axis is clamped so content can't overflow it. */
7
+ orientation?: ScrollOrientation;
8
+ }
9
+
10
+ /**
11
+ * `<kai-scroll-area>` — a scroll container with a themed, thin, cross-browser
12
+ * scrollbar and a keyboard-reachable region. Project the scrollable content as
13
+ * light-DOM children and give the element a bounded size in your layout; the
14
+ * content then scrolls inside. Use `orientation` to pick the axis. Restyle the
15
+ * container via `::part(viewport)`; the scrollbar follows the
16
+ * `--color-scrollbar-thumb` token.
17
+ *
18
+ * ```html
19
+ * <kai-scroll-area style="height: 16rem">…long content…</kai-scroll-area>
20
+ * <kai-scroll-area orientation="horizontal" style="max-width: 24rem">…wide row…</kai-scroll-area>
21
+ * ```
22
+ */
23
+ defineWebComponent<Props>('kai-scroll-area', {
24
+ orientation: 'vertical',
25
+ }, (props) => (
26
+ <>
27
+ {/* The element is a block box; the consumer sets its size, the viewport fills it. */}
28
+ <style>{':host{display:block;min-height:0}'}</style>
29
+ <ScrollArea class="h-full max-h-full w-full max-w-full" part="viewport" orientation={props.orientation as ScrollOrientation}>
30
+ <slot />
31
+ </ScrollArea>
32
+ </>
33
+ ));
@@ -0,0 +1,180 @@
1
+ import { createEffect, createSignal, untrack, Show } from 'solid-js';
2
+ import { defineWebComponent } from './define';
3
+ import { Input } from '../ui/input';
4
+ import { Kbd } from '../ui/kbd';
5
+ import { Loader } from '../components/loader';
6
+ import { renderIcon } from '../ui/icon';
7
+
8
+ interface Props extends Record<string, unknown> {
9
+ /** Controlled query — settable and reflected to the `value` attribute. Read
10
+ * `el.value` for live state. */
11
+ value?: string;
12
+ /** Placeholder. Defaults to `Search…`. */
13
+ placeholder?: string;
14
+ /** Leading icon-NAME string (a curated name, URL, or text), resolved to a glyph
15
+ * the same way `kai-button`'s `icon` is. Defaults to `search`. */
16
+ icon?: string;
17
+ /** Debounce window for `kai-search`, in ms. Defaults to `200`. */
18
+ debounce?: number;
19
+ /** Show a spinner in place of the leading icon while results load. */
20
+ loading?: boolean;
21
+ /** Optional shortcut hint shown (as a `kai-kbd`) while the field is empty,
22
+ * e.g. `Mod+K`. Display only; it does not bind the key. */
23
+ shortcut?: string;
24
+ }
25
+
26
+ /** Events fired by `<kai-search>`. */
27
+ interface Events {
28
+ /** The query changed (debounced live, and on clear). */
29
+ 'kai-search': { value: string };
30
+ /** Enter was pressed. */
31
+ 'kai-submit': { value: string };
32
+ /** The field committed (blur). */
33
+ 'kai-change': { value: string };
34
+ }
35
+
36
+ /**
37
+ * `<kai-search>` — a debounced filter field built on `kai-input`. Type to fire a
38
+ * debounced `kai-search`, press Enter for `kai-submit`. A clear (×) button shows
39
+ * once there's a value; an optional `shortcut` renders a `kai-kbd` hint while the
40
+ * field is empty.
41
+ *
42
+ * ```html
43
+ * <kai-search placeholder="Search docs" shortcut="Mod+K"></kai-search>
44
+ * <script type="module">
45
+ * import '@kitn.ai/ui/elements';
46
+ * const s = document.querySelector('kai-search');
47
+ * s.addEventListener('kai-search', (e) => filter(e.detail.value));
48
+ * s.addEventListener('kai-submit', (e) => go(e.detail.value));
49
+ * </script>
50
+ * ```
51
+ *
52
+ * Drive/read the query with the `value` property (reflected to the attribute).
53
+ * Restyle via `::part(field)`, `::part(input)`, and `::part(clear)`.
54
+ */
55
+ defineWebComponent<Props, Events>('kai-search', {
56
+ value: undefined,
57
+ placeholder: 'Search…',
58
+ icon: 'search',
59
+ debounce: 200,
60
+ loading: false,
61
+ shortcut: undefined,
62
+ }, (props, ctx) => {
63
+ const { element, dispatch, flag, expose } = ctx;
64
+
65
+ // Lift the query into the facade and drive Input CONTROLLED so the host can read
66
+ // it (`el.value` / `:host([value])`) and set it after mount. Mirrors kai-segmented.
67
+ const [value, setValue] = createSignal(
68
+ (props.value as string | undefined) ?? element.getAttribute('value') ?? '',
69
+ );
70
+
71
+ const coerce = (v: unknown): string =>
72
+ v == null ? (element.getAttribute('value') ?? '') : String(v);
73
+
74
+ // Reads return LIVE state; host writes (`el.value = …`) drive it WITHOUT firing
75
+ // events. The equality guard kills the reflect write-back loop.
76
+ Object.defineProperty(element, 'value', {
77
+ get: () => value(),
78
+ set: (v: unknown) => { const next = coerce(v); if (untrack(value) !== next) setValue(next); },
79
+ configurable: true,
80
+ enumerable: true,
81
+ });
82
+
83
+ // Reflect internal value → `[value]` host attribute (for `:host([value])`).
84
+ createEffect(() => {
85
+ const v = value();
86
+ if (v) {
87
+ if (element.getAttribute('value') !== v) element.setAttribute('value', v);
88
+ } else if (element.hasAttribute('value')) {
89
+ element.removeAttribute('value');
90
+ }
91
+ });
92
+
93
+ // Debounced kai-search: each keystroke resets the timer; it fires once after the
94
+ // window. Clearing fires immediately (timer cancelled).
95
+ let timer: ReturnType<typeof setTimeout> | undefined;
96
+ const debounceMs = () => {
97
+ const ms = Number(props.debounce ?? 200);
98
+ return Number.isFinite(ms) && ms >= 0 ? ms : 200;
99
+ };
100
+ const scheduleSearch = (next: string) => {
101
+ if (timer) clearTimeout(timer);
102
+ timer = setTimeout(() => dispatch('kai-search', { value: next }), debounceMs());
103
+ };
104
+
105
+ const getInput = (): HTMLInputElement | null =>
106
+ element.shadowRoot?.querySelector<HTMLInputElement>('input') ?? null;
107
+
108
+ const onInput = (next: string) => {
109
+ setValue(next);
110
+ scheduleSearch(next);
111
+ };
112
+
113
+ // Empty the field, fire kai-search '' immediately (cancelling any pending), refocus.
114
+ const clear = () => {
115
+ if (timer) clearTimeout(timer);
116
+ setValue('');
117
+ dispatch('kai-search', { value: '' });
118
+ getInput()?.focus();
119
+ };
120
+
121
+ const onKeyDown = (e: KeyboardEvent) => {
122
+ if (e.key === 'Enter') dispatch('kai-submit', { value: untrack(value) });
123
+ };
124
+
125
+ expose({
126
+ focus: () => getInput()?.focus(),
127
+ clear,
128
+ });
129
+
130
+ // Leading: a spinner while loading, otherwise the resolved icon glyph.
131
+ const leading = (
132
+ <Show
133
+ when={flag('loading')}
134
+ fallback={renderIcon((props.icon as string) ?? 'search', {
135
+ class: 'size-4 shrink-0',
136
+ imgClass: 'size-4 shrink-0',
137
+ spanClass: 'inline-flex size-4 shrink-0 items-center justify-center',
138
+ ariaHidden: true,
139
+ })}
140
+ >
141
+ <Loader variant="circular" size="sm" />
142
+ </Show>
143
+ );
144
+
145
+ // Trailing: a clear button once there's a value, else a shortcut hint if set.
146
+ const trailing = (
147
+ <>
148
+ <Show when={value()}>
149
+ <button
150
+ type="button"
151
+ part="clear"
152
+ aria-label="Clear"
153
+ class="inline-flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
154
+ onClick={clear}
155
+ >
156
+ {renderIcon('x', { class: 'size-4', imgClass: 'size-4' })}
157
+ </button>
158
+ </Show>
159
+ <Show when={!value() && props.shortcut}>
160
+ <Kbd keys={props.shortcut as string} size="sm" class="opacity-80" />
161
+ </Show>
162
+ </>
163
+ );
164
+
165
+ return (
166
+ <>
167
+ <style>{':host{display:block}'}</style>
168
+ <Input
169
+ type="search"
170
+ value={value()}
171
+ placeholder={(props.placeholder as string) ?? 'Search…'}
172
+ leading={leading}
173
+ trailing={trailing}
174
+ onValueInput={onInput}
175
+ onValueChange={(v) => dispatch('kai-change', { value: v })}
176
+ onKeyDown={onKeyDown}
177
+ />
178
+ </>
179
+ );
180
+ });
@@ -0,0 +1,135 @@
1
+ import { createEffect, createSignal, untrack } from 'solid-js';
2
+ import { defineWebComponent } from './define';
3
+ import { Segmented, type SegmentedOption } from '../ui/segmented';
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
+ }
14
+
15
+ interface Props extends Record<string, unknown> {
16
+ /** 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`
19
+ * attribute. `el.value = 'preview'` drives it; choosing a segment updates it
20
+ * and fires `kai-change`. Read `el.value` for live state. */
21
+ value?: string;
22
+ /** Control density: `sm` or `md`. Defaults to `md`. */
23
+ size?: 'sm' | 'md';
24
+ }
25
+
26
+ /** Events fired by `<kai-segmented>`. */
27
+ interface Events {
28
+ /** A segment was chosen. */
29
+ 'kai-change': { value: string };
30
+ }
31
+
32
+ /**
33
+ * `<kai-segmented>` — a single-select pill track (segmented / toggle group).
34
+ * Feed it `options` (a JS-property array), drive/read the selection with the
35
+ * `value` property (settable + reflected to the `value` attribute, so
36
+ * `:host([value])` and `el.value` see live state), and listen for `kai-change`.
37
+ *
38
+ * ```html
39
+ * <kai-segmented value="preview"></kai-segmented>
40
+ * <script type="module">
41
+ * import '@kitn.ai/ui/elements';
42
+ * const seg = document.querySelector('kai-segmented');
43
+ * seg.options = [
44
+ * { value: 'code', label: 'Code', icon: 'code' },
45
+ * { value: 'preview', label: 'Preview', icon: 'monitor' },
46
+ * ];
47
+ * seg.addEventListener('kai-change', (e) => console.log(e.detail.value));
48
+ * seg.value = 'code'; // drive it (no kai-change — the host already knows)
49
+ * </script>
50
+ * ```
51
+ *
52
+ * Each option's `icon` is an icon-name string resolved to a glyph (curated name,
53
+ * URL, or text). Restyle via `::part(track)` and `::part(segment)`.
54
+ */
55
+ defineWebComponent<Props, Events>('kai-segmented', {
56
+ options: [],
57
+ value: undefined,
58
+ size: 'md',
59
+ }, (props, ctx) => {
60
+ const { element, dispatch } = ctx;
61
+
62
+ // Lift the selected value into the facade and drive Segmented CONTROLLED so the
63
+ // host can read it (`el.value` / `:host([value])`) and set it after mount. Seed
64
+ // from the `value` property/attribute present on mount (options usually arrive
65
+ // as a property after upgrade, so we don't auto-select the first segment here).
66
+ const [value, setValue] = createSignal(
67
+ (props.value as string | undefined) ?? element.getAttribute('value') ?? '',
68
+ );
69
+
70
+ // Coerce any value coming through the `value` setter (a JS assignment, or the
71
+ // write-back from `attributeChangedCallback`) to a string — falling back to the
72
+ // live attribute when it's nullish, so the reflect write-back equals the signal
73
+ // and the equality guards below absorb it (no attr⇄prop feedback loop; mirrors
74
+ // kai-switch's `checked`).
75
+ const coerce = (v: unknown): string =>
76
+ v == null ? (element.getAttribute('value') ?? '') : String(v);
77
+
78
+ // Apply a new value and fire kai-change once (the user-choice path).
79
+ const apply = (next: string) => {
80
+ if (untrack(value) === next) return;
81
+ setValue(next);
82
+ dispatch('kai-change', { value: next });
83
+ };
84
+
85
+ // Override the `value` property so reads return LIVE state (the signal) and host
86
+ // writes (`el.value = …`) drive it WITHOUT firing kai-change — distinct from the
87
+ // user-choice path. The equality guard kills the reflect write-back loop.
88
+ Object.defineProperty(element, 'value', {
89
+ get: () => value(),
90
+ set: (v: unknown) => { const next = coerce(v); if (untrack(value) !== next) setValue(next); },
91
+ configurable: true,
92
+ enumerable: true,
93
+ });
94
+
95
+ // Reflect internal value → the `[value]` host attribute (for `:host([value])`).
96
+ // The guard against the live attribute keeps the write-back the reflect triggers
97
+ // (attributeChangedCallback → setter) from looping.
98
+ createEffect(() => {
99
+ const v = value();
100
+ if (v) {
101
+ if (element.getAttribute('value') !== v) element.setAttribute('value', v);
102
+ } else if (element.hasAttribute('value')) {
103
+ element.removeAttribute('value');
104
+ }
105
+ });
106
+
107
+ // Resolve each option's icon-NAME string into a rendered glyph, the same path
108
+ // kai-button uses for its `icon` prop, and hand the primitive `{value,label,icon:JSX}`.
109
+ const resolved = (): SegmentedOption[] =>
110
+ (props.options ?? []).map((o) => ({
111
+ value: o.value,
112
+ label: o.label,
113
+ icon: o.icon
114
+ ? renderIcon(o.icon, {
115
+ class: 'size-4 shrink-0',
116
+ imgClass: 'size-4 shrink-0',
117
+ spanClass: 'inline-flex size-4 shrink-0 items-center justify-center',
118
+ ariaHidden: true,
119
+ })
120
+ : undefined,
121
+ }));
122
+
123
+ return (
124
+ <>
125
+ {/* Base sets `:host{display:block}`; the track flows inline like a pill. */}
126
+ <style>{':host{display:inline-flex}'}</style>
127
+ <Segmented
128
+ options={resolved()}
129
+ value={value()}
130
+ size={(props.size as 'sm' | 'md' | undefined) ?? 'md'}
131
+ onChange={(next) => apply(next)}
132
+ />
133
+ </>
134
+ );
135
+ });
@@ -0,0 +1,36 @@
1
+ import { Separator } from '../ui/separator';
2
+ import { defineWebComponent } from './define';
3
+
4
+ interface Props extends Record<string, unknown> {
5
+ /** `horizontal` (default, block + full-width) or `vertical` (a rule inside a
6
+ * flex/grid row — it stretches to the row height). */
7
+ orientation?: 'horizontal' | 'vertical';
8
+ }
9
+
10
+ /**
11
+ * `<kai-separator>` — a themed divider between groups of content (toolbar
12
+ * sections, menu groups, header/sidebar splits). Carries `role="separator"`.
13
+ * Restyle via `::part(separator)`.
14
+ *
15
+ * ```html
16
+ * <kai-separator></kai-separator>
17
+ * <div style="display:flex; gap:.5rem">
18
+ * <span>A</span><kai-separator orientation="vertical"></kai-separator><span>B</span>
19
+ * </div>
20
+ * ```
21
+ */
22
+ defineWebComponent<Props>('kai-separator', {
23
+ orientation: 'horizontal',
24
+ }, (props) => {
25
+ const vertical = () => props.orientation === 'vertical';
26
+ return (
27
+ <>
28
+ {/* The host owns its layout box: a horizontal rule is block + full-width;
29
+ a vertical rule is an inline-block flex item that stretches to the row. */}
30
+ <style>{vertical()
31
+ ? ':host{display:inline-block;align-self:stretch}'
32
+ : ':host{display:block}'}</style>
33
+ <Separator orientation={vertical() ? 'vertical' : 'horizontal'} part="separator" />
34
+ </>
35
+ );
36
+ });
@@ -0,0 +1,50 @@
1
+ import { createSignal, onCleanup, onMount } from 'solid-js';
2
+ import { SettingItem } from '../ui/settings-group';
3
+ import { defineWebComponent } from './define';
4
+
5
+ interface Props extends Record<string, unknown> {
6
+ /** Row label (primary text). Attribute: `label`. */
7
+ label?: string;
8
+ /** Optional secondary description under the label. Attribute: `description`. */
9
+ description?: string;
10
+ }
11
+
12
+ /**
13
+ * `<kai-setting-item>` — one row inside a `<kai-settings-group>`: a left
14
+ * label/description block and an optional right-aligned control. Slot the control
15
+ * (a `<kai-switch>`, segmented control, select, …) into `slot="control"`; omit it
16
+ * for a plain label row.
17
+ *
18
+ * Themeable `::part`s: `label` (the label/description block) and `control`.
19
+ *
20
+ * ```html
21
+ * <kai-setting-item label="Reduce motion" description="Minimize animations.">
22
+ * <kai-switch slot="control"></kai-switch>
23
+ * </kai-setting-item>
24
+ * ```
25
+ */
26
+ defineWebComponent<Props>('kai-setting-item', {
27
+ label: '',
28
+ description: undefined,
29
+ }, (props, { element }) => {
30
+ // The control region only renders when `slot="control"` is actually filled, so
31
+ // a plain label row has no stray right-side wrapper. An empty `<slot>` is always
32
+ // a truthy node, so we track occupancy and gate on it (the kai-card approach).
33
+ // Re-read on child/attribute mutations so a late-slotted control lights up.
34
+ const [hasControl, setHasControl] = createSignal(false);
35
+ onMount(() => {
36
+ const read = () => setHasControl(!!element.querySelector(':scope > [slot="control"]'));
37
+ read();
38
+ const observer = new MutationObserver(read);
39
+ observer.observe(element, { childList: true, attributes: true, subtree: true });
40
+ onCleanup(() => observer.disconnect());
41
+ });
42
+
43
+ return (
44
+ <SettingItem
45
+ label={props.label ?? ''}
46
+ description={props.description}
47
+ control={hasControl() ? <slot name="control" /> : undefined}
48
+ />
49
+ );
50
+ });