@kitn.ai/ui 0.17.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 (494) hide show
  1. package/README.md +28 -5
  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 +37 -12
  9. package/dist/components/choice-card.d.ts +26 -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/file-tree.d.ts +15 -0
  19. package/dist/components/form.d.ts +34 -0
  20. package/dist/components/markdown.d.ts +3 -0
  21. package/dist/components/message.d.ts +12 -0
  22. package/dist/components/model-switcher.d.ts +7 -0
  23. package/dist/components/prompt-input.d.ts +13 -4
  24. package/dist/components/prompt-suggestion.d.ts +9 -1
  25. package/dist/components/reasoning.d.ts +14 -1
  26. package/dist/components/response-compare.d.ts +14 -0
  27. package/dist/components/screen.d.ts +46 -0
  28. package/dist/components/tasks-card.d.ts +49 -1
  29. package/dist/components/toast.d.ts +12 -2
  30. package/dist/components/tool-types.d.ts +10 -0
  31. package/dist/components/tool.d.ts +8 -8
  32. package/dist/components/voice-input.d.ts +27 -0
  33. package/dist/components/voice-output.d.ts +33 -0
  34. package/dist/core-C8fzo39E.js +12 -0
  35. package/dist/custom-elements.json +8392 -1860
  36. package/dist/elements/agent-card.d.ts +1 -0
  37. package/dist/elements/agent-card.js +1 -0
  38. package/dist/elements/artifact.js +1 -1
  39. package/dist/elements/attachments.js +1 -1
  40. package/dist/elements/autoloader.js +1 -1
  41. package/dist/elements/avatar.d.ts +1 -0
  42. package/dist/elements/avatar.js +1 -0
  43. package/dist/elements/badge.d.ts +1 -0
  44. package/dist/elements/badge.js +1 -0
  45. package/dist/elements/button.d.ts +1 -0
  46. package/dist/elements/button.js +1 -0
  47. package/dist/elements/card.js +1 -1
  48. package/dist/elements/cards.js +1 -1
  49. package/dist/elements/chain-of-thought.js +1 -1
  50. package/dist/elements/chat-scope-picker.js +1 -1
  51. package/dist/elements/chat-types.d.ts +47 -0
  52. package/dist/elements/chat-workspace.js +1 -1
  53. package/dist/elements/chat.js +1 -1
  54. package/dist/elements/checkpoint.js +1 -1
  55. package/dist/elements/choice.js +1 -1
  56. package/dist/elements/chunks/Icon-DLLBeLG5.js +1 -0
  57. package/dist/elements/chunks/action-icons-UB4V5FNq.js +1 -0
  58. package/dist/elements/chunks/arrow-left-C-gwlUmx.js +1 -0
  59. package/dist/elements/chunks/attachments-CgbErf1r.js +1 -0
  60. package/dist/elements/chunks/badge-DTQpgB6N.js +1 -0
  61. package/dist/elements/chunks/button-XDUM6lXs.js +1 -0
  62. package/dist/elements/chunks/card-CBlFZ-7I.js +1 -0
  63. package/dist/elements/chunks/chat-thread-BIhmqwNL.js +1 -0
  64. package/dist/elements/chunks/check-hGUoVIKb.js +1 -0
  65. package/dist/elements/chunks/chevron-down-DDoaSUtO.js +1 -0
  66. package/dist/elements/chunks/chevron-right-CdGEUakB.js +1 -0
  67. package/dist/elements/chunks/circle-BKAZdmzb.js +1 -0
  68. package/dist/elements/chunks/circle-check-CmYG-y3I.js +1 -0
  69. package/dist/elements/chunks/circle-x-DewgAEym.js +1 -0
  70. package/dist/elements/chunks/cn-CU7UAWzk.js +1 -0
  71. package/dist/elements/chunks/code-block-DedwxwFI.js +1 -0
  72. package/dist/elements/chunks/collapsible-FfgmTHtM.js +1 -0
  73. package/dist/elements/chunks/composer-Cfbw5HKT.js +65 -0
  74. package/dist/elements/chunks/context-DwJmxlRE.js +1 -0
  75. package/dist/elements/chunks/conversation-list-DsCQMfPq.js +1 -0
  76. package/dist/elements/chunks/default-input-BuqsoENC.js +1 -0
  77. package/dist/elements/chunks/define-rGsaWsLL.js +1 -0
  78. package/dist/elements/chunks/disclosure-CwoAkpMH.js +1 -0
  79. package/dist/elements/chunks/download-DJ06G3Bz.js +1 -0
  80. package/dist/elements/chunks/dropdown-BFg8ri_R.js +1 -0
  81. package/dist/elements/chunks/ellipsis-dlN6YvGw.js +1 -0
  82. package/dist/elements/chunks/external-link-DBX2lc_R.js +1 -0
  83. package/dist/elements/chunks/file-text-HfwUx4F9.js +1 -0
  84. package/dist/elements/chunks/file-tree-C6Toj71u.js +1 -0
  85. package/dist/elements/chunks/folder-MYuqa9Xp.js +1 -0
  86. package/dist/elements/chunks/hover-card-gE7iyXdW.js +1 -0
  87. package/dist/elements/chunks/icon-Vqz4ivrY.js +1 -0
  88. package/dist/elements/chunks/{index-CTBEJeo6.js → index-BCRhi84a.js} +1 -1
  89. package/dist/elements/chunks/info-B_toFS0l.js +1 -0
  90. package/dist/elements/chunks/input-gzbHYZvQ.js +1 -0
  91. package/dist/elements/chunks/kbd-n49c4KZm.js +1 -0
  92. package/dist/elements/chunks/link-CKPs9yM0.js +1 -0
  93. package/dist/elements/chunks/loader-q6MamGus.js +1 -0
  94. package/dist/elements/chunks/{markdown-CMTGx9r8.js → markdown-DBrcqq4S.js} +9 -9
  95. package/dist/elements/chunks/message-CTqaYI0s.js +1 -0
  96. package/dist/elements/chunks/message-feedback-Cvzm03w0.js +1 -0
  97. package/dist/elements/chunks/message-square-CUg9eRCi.js +1 -0
  98. package/dist/elements/chunks/minimize-2-l2klxP6K.js +1 -0
  99. package/dist/elements/chunks/model-switcher-CmyjiHO1.js +1 -0
  100. package/dist/elements/chunks/overlay-C8sOYqjT.js +1 -0
  101. package/dist/elements/chunks/paperclip-42Ia7xHD.js +1 -0
  102. package/dist/elements/chunks/progress-bar-tzKMWAwO.js +1 -0
  103. package/dist/elements/chunks/prompt-suggestion-D3F6vP_A.js +1 -0
  104. package/dist/elements/chunks/reasoning-BJNmmyov.js +1 -0
  105. package/dist/elements/chunks/resizable-BRsk19qI.js +1 -0
  106. package/dist/elements/chunks/rotate-cw-BgcggLHC.js +1 -0
  107. package/dist/elements/chunks/scroll-area-CgGbFFbT.js +1 -0
  108. package/dist/elements/chunks/separator-8hM4GdHE.js +1 -0
  109. package/dist/elements/chunks/settings-CaUIYOg-.js +1 -0
  110. package/dist/elements/chunks/settings-group-CYjOVIZQ.js +1 -0
  111. package/dist/elements/chunks/share-BTYM3Ddt.js +1 -0
  112. package/dist/elements/chunks/skeleton-DsTYrPUe.js +1 -0
  113. package/dist/elements/chunks/slots-DkZ-Cmha.js +1 -0
  114. package/dist/elements/chunks/star-9R3LBQ9n.js +1 -0
  115. package/dist/elements/chunks/store-CYl5Y0_u.js +1 -0
  116. package/dist/elements/chunks/text-shimmer-CaYGv8Se.js +1 -0
  117. package/dist/elements/chunks/textarea-NEr2SLcD.js +1 -0
  118. package/dist/elements/chunks/thumbs-up-DZYZkFfc.js +1 -0
  119. package/dist/elements/chunks/toast-store-ClxVZRcc.js +1 -0
  120. package/dist/elements/chunks/tool-CHZOmoe9.js +1 -0
  121. package/dist/elements/chunks/tooltip-WpHElELC.js +1 -0
  122. package/dist/elements/chunks/triangle-alert-BlS80PUg.js +1 -0
  123. package/dist/elements/chunks/use-card-resolution-VSVoxDeJ.js +1 -0
  124. package/dist/elements/chunks/video-DxTPZqT8.js +1 -0
  125. package/dist/elements/chunks/x-C1qtndxn.js +1 -0
  126. package/dist/elements/coachmark.d.ts +1 -0
  127. package/dist/elements/coachmark.js +1 -0
  128. package/dist/elements/code-block.js +1 -1
  129. package/dist/elements/command.d.ts +1 -0
  130. package/dist/elements/command.js +1 -0
  131. package/dist/elements/compare.js +1 -1
  132. package/dist/elements/composer.d.ts +1 -0
  133. package/dist/elements/composer.js +1 -0
  134. package/dist/elements/confirm-card.js +1 -1
  135. package/dist/elements/context-meter.js +1 -1
  136. package/dist/elements/conversation-list.js +1 -1
  137. package/dist/elements/css.d.ts +1 -0
  138. package/dist/elements/default-input.d.ts +51 -0
  139. package/dist/elements/define.d.ts +53 -0
  140. package/dist/elements/dialog.d.ts +1 -0
  141. package/dist/elements/dialog.js +1 -0
  142. package/dist/elements/disclosure.d.ts +37 -0
  143. package/dist/elements/editable-label.d.ts +1 -0
  144. package/dist/elements/editable-label.js +1 -0
  145. package/dist/elements/embed.js +1 -1
  146. package/dist/elements/empty.js +1 -1
  147. package/dist/elements/feedback-bar.js +1 -1
  148. package/dist/elements/file-tree.js +1 -1
  149. package/dist/elements/file-upload.js +1 -1
  150. package/dist/elements/form.js +1 -1
  151. package/dist/elements/hover-card.d.ts +1 -0
  152. package/dist/elements/hover-card.js +1 -0
  153. package/dist/elements/icon.d.ts +1 -0
  154. package/dist/elements/icon.js +1 -0
  155. package/dist/elements/image.js +1 -1
  156. package/dist/elements/input.d.ts +1 -0
  157. package/dist/elements/input.js +1 -0
  158. package/dist/elements/kbd.d.ts +1 -0
  159. package/dist/elements/kbd.js +1 -0
  160. package/dist/elements/link-preview.js +1 -1
  161. package/dist/elements/loader.js +1 -1
  162. package/dist/elements/markdown.js +1 -1
  163. package/dist/elements/menu.d.ts +1 -0
  164. package/dist/elements/menu.js +1 -0
  165. package/dist/elements/message-skills.js +1 -1
  166. package/dist/elements/message.js +1 -1
  167. package/dist/elements/model-switcher.js +1 -1
  168. package/dist/elements/nav.d.ts +1 -0
  169. package/dist/elements/nav.js +1 -0
  170. package/dist/elements/notice.d.ts +1 -0
  171. package/dist/elements/notice.js +1 -0
  172. package/dist/elements/pane-group.d.ts +1 -0
  173. package/dist/elements/pane-group.js +1 -0
  174. package/dist/elements/pane.d.ts +1 -0
  175. package/dist/elements/pane.js +1 -0
  176. package/dist/elements/popover.js +1 -1
  177. package/dist/elements/progress-bar.d.ts +1 -0
  178. package/dist/elements/progress-bar.js +1 -0
  179. package/dist/elements/prompt-dock.d.ts +1 -0
  180. package/dist/elements/prompt-dock.js +1 -0
  181. package/dist/elements/prompt-input.js +1 -1
  182. package/dist/elements/prompt-suggestions.js +1 -1
  183. package/dist/elements/reasoning.js +1 -1
  184. package/dist/elements/register-impl.d.ts +0 -0
  185. package/dist/elements/register.d.ts +13 -0
  186. package/dist/elements/remote.d.ts +1 -0
  187. package/dist/elements/remote.js +1 -0
  188. package/dist/elements/resizable.js +1 -1
  189. package/dist/elements/response-stream.js +2 -2
  190. package/dist/elements/screen.d.ts +1 -0
  191. package/dist/elements/screen.js +1 -0
  192. package/dist/elements/scroll-area.d.ts +1 -0
  193. package/dist/elements/scroll-area.js +1 -0
  194. package/dist/elements/scroll-button.js +1 -1
  195. package/dist/elements/search.d.ts +1 -0
  196. package/dist/elements/search.js +1 -0
  197. package/dist/elements/segmented.d.ts +1 -0
  198. package/dist/elements/segmented.js +1 -0
  199. package/dist/elements/separator.d.ts +1 -0
  200. package/dist/elements/separator.js +1 -0
  201. package/dist/elements/setting-item.d.ts +1 -0
  202. package/dist/elements/setting-item.js +1 -0
  203. package/dist/elements/settings-group.d.ts +1 -0
  204. package/dist/elements/settings-group.js +1 -0
  205. package/dist/elements/skeleton.d.ts +1 -0
  206. package/dist/elements/skeleton.js +1 -0
  207. package/dist/elements/slots.d.ts +176 -0
  208. package/dist/elements/source.js +1 -1
  209. package/dist/elements/status.d.ts +1 -0
  210. package/dist/elements/status.js +1 -0
  211. package/dist/elements/switch.js +1 -1
  212. package/dist/elements/tabs.d.ts +1 -0
  213. package/dist/elements/tabs.js +1 -0
  214. package/dist/elements/tasks.js +1 -1
  215. package/dist/elements/text-shimmer.js +1 -1
  216. package/dist/elements/thinking-bar.js +1 -1
  217. package/dist/elements/toast.js +1 -1
  218. package/dist/elements/tool.js +1 -1
  219. package/dist/elements/tooltip.d.ts +1 -0
  220. package/dist/elements/tooltip.js +1 -0
  221. package/dist/elements/voice-input.js +1 -1
  222. package/dist/elements/voice-output.d.ts +1 -0
  223. package/dist/elements/voice-output.js +1 -0
  224. package/dist/elements.d.ts +733 -58
  225. package/dist/engine-javascript-C1x7zo1_.js +141 -0
  226. package/dist/index.d.ts +3 -2
  227. package/dist/index.js +8256 -5703
  228. package/dist/kai.es.js +1 -0
  229. package/dist/llms/llms-full.txt +1146 -64
  230. package/dist/llms/llms.txt +4 -4
  231. package/dist/mcp.es.js +62 -7
  232. package/dist/primitives/composer-model.d.ts +22 -0
  233. package/dist/primitives/composer-triggers.d.ts +19 -0
  234. package/dist/primitives/create-kai-chat.d.ts +38 -0
  235. package/dist/primitives/toast-store.d.ts +32 -2
  236. package/dist/primitives/use-speech-recognition.d.ts +26 -0
  237. package/dist/react/index.d.ts +1085 -97
  238. package/dist/react/runtime.d.ts +9 -2
  239. package/dist/react/use-kai-chat.d.ts +41 -0
  240. package/dist/react.js +572 -193
  241. package/dist/register-impl-CYWGkgbI.js +141 -0
  242. package/dist/schemas/tasks.schema.json +2 -2
  243. package/dist/state/index.d.ts +4 -0
  244. package/dist/state/messages.d.ts +11 -0
  245. package/dist/state/stream.d.ts +22 -0
  246. package/dist/state/suggestions.d.ts +4 -0
  247. package/dist/state.js +117 -0
  248. package/dist/theme.tokens.css +87 -0
  249. package/dist/types.d.ts +4 -0
  250. package/dist/ui/agent-card.d.ts +61 -0
  251. package/dist/ui/button.d.ts +5 -2
  252. package/dist/ui/card.d.ts +61 -0
  253. package/dist/ui/collapsible.d.ts +15 -1
  254. package/dist/ui/command.d.ts +33 -0
  255. package/dist/ui/dialog.d.ts +42 -0
  256. package/dist/ui/dropdown.d.ts +95 -1
  257. package/dist/ui/editable-label.d.ts +26 -0
  258. package/dist/ui/hover-card.d.ts +13 -1
  259. package/dist/ui/icon.d.ts +18 -0
  260. package/dist/ui/input.d.ts +33 -0
  261. package/dist/ui/kbd.d.ts +21 -0
  262. package/dist/ui/nav.d.ts +62 -0
  263. package/dist/ui/notice.d.ts +31 -0
  264. package/dist/ui/overlay.d.ts +12 -0
  265. package/dist/ui/pane-grid.d.ts +58 -0
  266. package/dist/ui/pane-group.d.ts +75 -0
  267. package/dist/ui/pane.d.ts +78 -0
  268. package/dist/ui/popover.d.ts +11 -1
  269. package/dist/ui/progress-bar.d.ts +23 -0
  270. package/dist/ui/prompt-dock.d.ts +96 -0
  271. package/dist/ui/resizable.d.ts +12 -0
  272. package/dist/ui/scroll-area.d.ts +4 -0
  273. package/dist/ui/segmented.d.ts +28 -0
  274. package/dist/ui/settings-group.d.ts +32 -0
  275. package/dist/ui/skeleton.d.ts +12 -0
  276. package/dist/ui/stat.d.ts +16 -0
  277. package/dist/ui/status.d.ts +13 -0
  278. package/dist/ui/switch.d.ts +8 -1
  279. package/dist/ui/tabs.d.ts +35 -0
  280. package/dist/ui/tooltip.d.ts +19 -1
  281. package/frameworks/react/index.tsx +1042 -157
  282. package/frameworks/react/runtime.tsx +30 -1
  283. package/frameworks/react/use-kai-chat.tsx +87 -0
  284. package/llms-full.txt +1146 -64
  285. package/llms.txt +4 -4
  286. package/package.json +23 -8
  287. package/src/agent-tooling/mcp/manifest.ts +14 -0
  288. package/src/agent-tooling/mcp/tools/debug.ts +10 -6
  289. package/src/agent-tooling/mcp/tools/reference.ts +32 -0
  290. package/src/agent-tooling/mcp/tools/scaffold.ts +30 -1
  291. package/src/components/artifact.tsx +98 -13
  292. package/src/components/attachment-types.ts +13 -0
  293. package/src/components/attachments.tsx +4 -14
  294. package/src/components/card.tsx +109 -15
  295. package/src/components/chain-of-thought.tsx +210 -1
  296. package/src/components/chat-scope-picker.tsx +13 -3
  297. package/src/components/chat-thread.tsx +225 -116
  298. package/src/components/choice-card.tsx +103 -11
  299. package/src/components/coachmark.tsx +245 -0
  300. package/src/components/component-meta.json +691 -102
  301. package/src/components/composer-dom.ts +159 -0
  302. package/src/components/composer-highlight.ts +242 -0
  303. package/src/components/composer-history.ts +82 -0
  304. package/src/components/composer.tsx +979 -0
  305. package/src/components/confirm-card.tsx +54 -1
  306. package/src/components/conversation-item.tsx +69 -7
  307. package/src/components/conversation-list.tsx +134 -37
  308. package/src/components/file-tree.tsx +197 -47
  309. package/src/components/form-widgets.tsx +9 -7
  310. package/src/components/form.tsx +140 -17
  311. package/src/components/image.tsx +3 -5
  312. package/src/components/link-preview.tsx +5 -4
  313. package/src/components/markdown.tsx +5 -2
  314. package/src/components/message.tsx +23 -4
  315. package/src/components/model-switcher.tsx +19 -4
  316. package/src/components/prompt-input.tsx +46 -75
  317. package/src/components/prompt-suggestion.tsx +48 -16
  318. package/src/components/reasoning.tsx +29 -6
  319. package/src/components/response-compare.tsx +31 -2
  320. package/src/components/screen.tsx +176 -0
  321. package/src/components/tasks-card.tsx +342 -21
  322. package/src/components/toast.tsx +119 -31
  323. package/src/components/tool-types.ts +10 -0
  324. package/src/components/tool.tsx +22 -16
  325. package/src/components/voice-input.tsx +102 -19
  326. package/src/components/voice-output.tsx +202 -0
  327. package/src/elements/agent-card.tsx +67 -0
  328. package/src/elements/artifact.tsx +53 -4
  329. package/src/elements/attachments.tsx +1 -0
  330. package/src/elements/avatar.tsx +33 -0
  331. package/src/elements/badge.tsx +32 -0
  332. package/src/elements/button.tsx +126 -0
  333. package/src/elements/card-media.jpg +0 -0
  334. package/src/elements/card.tsx +124 -31
  335. package/src/elements/cards.tsx +81 -7
  336. package/src/elements/chain-of-thought.tsx +77 -32
  337. package/src/elements/chat-scope-picker.tsx +35 -8
  338. package/src/elements/chat-types.ts +2 -2
  339. package/src/elements/chat-workspace.tsx +153 -41
  340. package/src/elements/chat.tsx +45 -23
  341. package/src/elements/choice.tsx +71 -19
  342. package/src/elements/coachmark.tsx +90 -0
  343. package/src/elements/command.tsx +209 -0
  344. package/src/elements/compare.tsx +24 -2
  345. package/src/elements/compiled.css +1 -1
  346. package/src/elements/composer.tsx +151 -0
  347. package/src/elements/confirm-card.tsx +36 -11
  348. package/src/elements/conversation-list.tsx +80 -11
  349. package/src/elements/default-input.tsx +75 -53
  350. package/src/elements/define.tsx +47 -6
  351. package/src/elements/dialog.tsx +98 -0
  352. package/src/elements/disclosure.ts +73 -0
  353. package/src/elements/editable-label.tsx +125 -0
  354. package/src/elements/element-manifest.json +129 -1
  355. package/src/elements/element-meta.json +5562 -1336
  356. package/src/elements/element-types.d.ts +732 -57
  357. package/src/elements/file-tree.tsx +12 -2
  358. package/src/elements/file-upload.tsx +1 -1
  359. package/src/elements/form.tsx +54 -11
  360. package/src/elements/hover-card.tsx +80 -0
  361. package/src/elements/icon-names.json +48 -0
  362. package/src/elements/icon.tsx +41 -0
  363. package/src/elements/input.tsx +203 -0
  364. package/src/elements/kbd.tsx +45 -0
  365. package/src/elements/menu.tsx +217 -0
  366. package/src/elements/message.tsx +58 -11
  367. package/src/elements/model-switcher.tsx +27 -1
  368. package/src/elements/nav.tsx +87 -0
  369. package/src/elements/notice.tsx +53 -0
  370. package/src/elements/pane-group.tsx +119 -0
  371. package/src/elements/pane.tsx +129 -0
  372. package/src/elements/popover.tsx +39 -17
  373. package/src/elements/progress-bar.tsx +39 -0
  374. package/src/elements/prompt-dock.tsx +81 -0
  375. package/src/elements/prompt-input.tsx +112 -63
  376. package/src/elements/prompt-suggestions.tsx +25 -9
  377. package/src/elements/reasoning.tsx +30 -9
  378. package/src/elements/register-impl.ts +38 -3
  379. package/src/elements/register.ts +11 -3
  380. package/src/elements/resizable.tsx +48 -11
  381. package/src/elements/screen.tsx +90 -0
  382. package/src/elements/scroll-area.tsx +33 -0
  383. package/src/elements/search.tsx +180 -0
  384. package/src/elements/segmented.tsx +135 -0
  385. package/src/elements/separator.tsx +36 -0
  386. package/src/elements/setting-item.tsx +50 -0
  387. package/src/elements/settings-group.tsx +37 -0
  388. package/src/elements/skeleton.tsx +45 -0
  389. package/src/elements/slots.ts +607 -0
  390. package/src/elements/source.tsx +13 -6
  391. package/src/elements/status.tsx +42 -0
  392. package/src/elements/switch.tsx +89 -14
  393. package/src/elements/tabs.tsx +95 -0
  394. package/src/elements/tasks.tsx +70 -14
  395. package/src/elements/toast.tsx +17 -2
  396. package/src/elements/tool.tsx +43 -9
  397. package/src/elements/tooltip.tsx +85 -0
  398. package/src/elements/video-poster.jpg +0 -0
  399. package/src/elements/voice-input.tsx +66 -16
  400. package/src/elements/voice-output.tsx +69 -0
  401. package/src/index.ts +5 -2
  402. package/src/primitives/card-schemas/tasks.schema.json +2 -2
  403. package/src/primitives/composer-model.ts +49 -0
  404. package/src/primitives/composer-triggers.ts +35 -0
  405. package/src/primitives/create-kai-chat.ts +66 -0
  406. package/src/primitives/toast-store.ts +43 -2
  407. package/src/primitives/use-speech-recognition.ts +135 -0
  408. package/src/state/index.ts +6 -0
  409. package/src/state/messages.ts +36 -0
  410. package/src/state/stream.ts +92 -0
  411. package/src/state/suggestions.ts +9 -0
  412. package/src/types.ts +4 -0
  413. package/src/ui/agent-card.tsx +212 -0
  414. package/src/ui/button.tsx +16 -5
  415. package/src/ui/card.tsx +245 -0
  416. package/src/ui/collapsible.tsx +30 -4
  417. package/src/ui/command.tsx +99 -0
  418. package/src/ui/dialog.tsx +217 -0
  419. package/src/ui/dropdown.tsx +375 -13
  420. package/src/ui/editable-label.tsx +112 -0
  421. package/src/ui/hover-card.tsx +28 -5
  422. package/src/ui/icon.tsx +110 -0
  423. package/src/ui/input.tsx +132 -0
  424. package/src/ui/kbd.tsx +118 -0
  425. package/src/ui/nav.tsx +282 -0
  426. package/src/ui/notice.tsx +84 -0
  427. package/src/ui/overlay.tsx +108 -2
  428. package/src/ui/pane-grid.tsx +116 -0
  429. package/src/ui/pane-group.tsx +280 -0
  430. package/src/ui/pane.tsx +193 -0
  431. package/src/ui/popover.tsx +16 -2
  432. package/src/ui/progress-bar.tsx +83 -0
  433. package/src/ui/prompt-dock.tsx +145 -0
  434. package/src/ui/resizable.tsx +69 -1
  435. package/src/ui/scroll-area.tsx +14 -3
  436. package/src/ui/segmented.tsx +109 -0
  437. package/src/ui/settings-group.tsx +67 -0
  438. package/src/ui/skeleton.tsx +62 -5
  439. package/src/ui/stat.tsx +41 -0
  440. package/src/ui/status.tsx +48 -0
  441. package/src/ui/switch.tsx +49 -23
  442. package/src/ui/tabs.tsx +168 -0
  443. package/src/ui/tooltip.tsx +52 -8
  444. package/theme.css +113 -0
  445. package/dist/components/slash-command.d.ts +0 -15
  446. package/dist/elements/chunks/Icon-D_Zmwmwh.js +0 -1
  447. package/dist/elements/chunks/action-icons-PVfIvcuG.js +0 -1
  448. package/dist/elements/chunks/attachments-Dp6vqtrc.js +0 -1
  449. package/dist/elements/chunks/button-CKyYD9G4.js +0 -1
  450. package/dist/elements/chunks/card-Cjho-PYk.js +0 -1
  451. package/dist/elements/chunks/chat-thread-RT808iPf.js +0 -1
  452. package/dist/elements/chunks/check-CDYaMYrM.js +0 -1
  453. package/dist/elements/chunks/chevron-down-3SBiq8HF.js +0 -1
  454. package/dist/elements/chunks/chevron-right-k2UFlIVK.js +0 -1
  455. package/dist/elements/chunks/cn-Dogu6PbV.js +0 -1
  456. package/dist/elements/chunks/code-block-BYUmfFSd.js +0 -1
  457. package/dist/elements/chunks/collapsible-BiNwdOn6.js +0 -1
  458. package/dist/elements/chunks/context-18g6oi4J.js +0 -1
  459. package/dist/elements/chunks/conversation-list-D9Y0NVdo.js +0 -1
  460. package/dist/elements/chunks/default-input-CSAoYYMd.js +0 -1
  461. package/dist/elements/chunks/download-D8K0Je8r.js +0 -1
  462. package/dist/elements/chunks/dropdown-bUs2iTia.js +0 -1
  463. package/dist/elements/chunks/external-link-6mA0wxab.js +0 -1
  464. package/dist/elements/chunks/file-text-DnaYk3Dm.js +0 -1
  465. package/dist/elements/chunks/file-tree-CgtRLlxK.js +0 -1
  466. package/dist/elements/chunks/hover-card-CIGw62gP.js +0 -1
  467. package/dist/elements/chunks/link-BlGSeoPy.js +0 -1
  468. package/dist/elements/chunks/loader-DvhR4qa0.js +0 -1
  469. package/dist/elements/chunks/message-CDZwXjhL.js +0 -1
  470. package/dist/elements/chunks/message-feedback-CYx81QiA.js +0 -1
  471. package/dist/elements/chunks/model-switcher-O_tUhoOT.js +0 -1
  472. package/dist/elements/chunks/overlay-DydXYMQW.js +0 -1
  473. package/dist/elements/chunks/prompt-suggestion-ldlWV5kd.js +0 -1
  474. package/dist/elements/chunks/reasoning-2PUnHlmr.js +0 -1
  475. package/dist/elements/chunks/resizable-B5WNbSeb.js +0 -1
  476. package/dist/elements/chunks/star-t9tI-P0q.js +0 -1
  477. package/dist/elements/chunks/store-C6rIooZz.js +0 -1
  478. package/dist/elements/chunks/text-shimmer-uh9V_KUh.js +0 -1
  479. package/dist/elements/chunks/textarea-3nm6Ia9U.js +0 -1
  480. package/dist/elements/chunks/thumbs-up-BBtguGld.js +0 -1
  481. package/dist/elements/chunks/toast-store-D8cL3fWl.js +0 -1
  482. package/dist/elements/chunks/tool-GJ3vwp1U.js +0 -1
  483. package/dist/elements/chunks/tooltip-DwKAz4XR.js +0 -1
  484. package/dist/elements/chunks/triangle-alert-Ct1zt2JL.js +0 -1
  485. package/dist/elements/chunks/use-card-resolution-D-_0Alzy.js +0 -1
  486. package/dist/elements/chunks/video-mVYiM99-.js +0 -1
  487. package/dist/elements/chunks/x-CzxL27Ch.js +0 -1
  488. package/dist/kitn-chat.es.js +0 -1
  489. package/dist/register-JyTglR6m.js +0 -1
  490. package/dist/register-impl-C6wlSsts.js +0 -77
  491. package/src/components/slash-command.tsx +0 -232
  492. package/src/elements/framework-usage.json +0 -588
  493. /package/dist/{kitn-chat-provider.d.ts → kai-provider.d.ts} +0 -0
  494. /package/dist/{kitn-chat-provider.es.js → kai-provider.es.js} +0 -0
@@ -2,12 +2,14 @@ import { defineWebComponent } from './define';
2
2
  import { FileTree, type FileTreeFile } from '../components/file-tree';
3
3
 
4
4
  interface Props extends Record<string, unknown> {
5
- /** The files to render. Set as a JS property (array of `{ path, url?, code?, language?, type? }`). */
5
+ /** The files to render. Set as a JS property (array of `{ path, url?, code?, language?, type?, additions?, deletions?, status? }`). */
6
6
  files: FileTreeFile[];
7
7
  /** Selected file path — highlighted in the tree. */
8
8
  activeFile?: string;
9
9
  /** Folder paths expanded initially. Omit to start with all folders open. */
10
10
  defaultExpanded?: string[];
11
+ /** Show a changed-files summary header (file count + summed `+/-` + Collapse-all). Attribute: `summary`. Off by default. */
12
+ summary?: boolean;
11
13
  }
12
14
 
13
15
  interface Events extends Record<string, unknown> {
@@ -19,12 +21,19 @@ interface Events extends Record<string, unknown> {
19
21
  * `<kai-file-tree>` — a collapsible, keyboard-navigable file explorer built from a
20
22
  * flat list of `/`-delimited paths (folders are derived). ARIA `tree`/`treeitem`.
21
23
  * Selecting a file fires a `select` event (`detail.path`). Fills its container.
24
+ *
25
+ * For a changed-files / diff view, give each file `additions`/`deletions`/`status`
26
+ * (rendered as trailing `+N`/`-N` stats and a colored status letter), and set the
27
+ * `summary` attribute for a header with the changed-file count, summed `+/-`, and a
28
+ * Collapse-all toggle. Restyle the diff bits via `::part(summary | status |
29
+ * stat-additions | stat-deletions)`.
22
30
  */
23
31
  defineWebComponent<Props, Events>('kai-file-tree', {
24
32
  files: [],
25
33
  activeFile: undefined,
26
34
  defaultExpanded: undefined,
27
- }, (props, { dispatch }) => (
35
+ summary: false,
36
+ }, (props, { dispatch, flag }) => (
28
37
  <>
29
38
  {/* Fill the container + own the scroll (see resizable.tsx fill technique:
30
39
  a definite `1fr` grid cell scoped to a wrapper, NOT :host, so the facade's
@@ -44,6 +53,7 @@ defineWebComponent<Props, Events>('kai-file-tree', {
44
53
  files={props.files}
45
54
  activeFile={props.activeFile}
46
55
  defaultExpanded={props.defaultExpanded}
56
+ summary={flag('summary')}
47
57
  onSelect={(path) => dispatch('kai-select', { path })}
48
58
  />
49
59
  </div>
@@ -36,7 +36,7 @@ defineWebComponent<Props, Events>('kai-file-upload', {
36
36
  disabled={flag('disabled')}
37
37
  onFilesAdded={(files) => dispatch('kai-files-added', { files })}
38
38
  >
39
- <FileUploadTrigger class="border-border bg-muted/30 hover:bg-muted/60 text-muted-foreground flex w-full cursor-pointer flex-col items-center justify-center gap-2 rounded-xl border border-dashed px-6 py-8 text-sm transition-colors">
39
+ <FileUploadTrigger class="border-border bg-surface hover:bg-muted/60 text-muted-foreground flex w-full cursor-pointer flex-col items-center justify-center gap-2 rounded-xl border border-dashed px-6 py-8 text-sm transition-colors">
40
40
  <Upload class="size-5" />
41
41
  <slot>{props.label}</slot>
42
42
  </FileUploadTrigger>
@@ -1,5 +1,5 @@
1
1
  import { defineWebComponent } from './define';
2
- import { Form, type FormDefinition } from '../components/form';
2
+ import { Form, type FormController, type FormDefinition } from '../components/form';
3
3
  import type { CardResolution } from '../primitives/card-contract';
4
4
 
5
5
  interface Props extends Record<string, unknown> {
@@ -15,6 +15,20 @@ interface Props extends Record<string, unknown> {
15
15
  /** Set when the user resolved this card; renders the read-only view. Property:
16
16
  * `el.resolution = { kind:'submit', data:{…} }`. */
17
17
  resolution?: Record<string, unknown>;
18
+ /** Controlled field values (JS property). When set, it wins over local edits. */
19
+ values?: Record<string, unknown>;
20
+ /** Initial values overlaying the schema defaults (uncontrolled seed; JS property). */
21
+ defaultValues?: Record<string, unknown>;
22
+ /** Disable all fields + submit. Attribute: `disabled`. */
23
+ disabled?: boolean;
24
+ }
25
+
26
+ /** Events fired by `<kai-form>`. (Resolution still flows up the bubbling `kai-card`
27
+ * contract event — `kai-values-change` is the live change signal, distinct from the
28
+ * terminal submit.) */
29
+ interface Events {
30
+ /** The form's values changed on input — current coerced values + validity. */
31
+ 'kai-values-change': { values: Record<string, unknown>; valid: boolean };
18
32
  }
19
33
 
20
34
  /**
@@ -27,17 +41,46 @@ interface Props extends Record<string, unknown> {
27
41
  * else the bubbling `kai-card` event (so a bare `<kai-form>` works without a host).
28
42
  * Isolated in Shadow DOM; theme-aware via the shared kit tokens.
29
43
  */
30
- defineWebComponent<Props>('kai-form', {
44
+ defineWebComponent<Props, Events>('kai-form', {
31
45
  data: undefined,
32
46
  cardId: undefined,
33
47
  heading: undefined,
34
48
  resolution: undefined,
35
- }, (props, { element }) => (
36
- <Form
37
- data={props.data as FormDefinition | undefined}
38
- cardId={props.cardId ?? (element.id || 'kai-form')}
39
- heading={props.heading}
40
- resolution={props.resolution as CardResolution | undefined}
41
- hostElement={element}
42
- />
43
- ));
49
+ values: undefined,
50
+ defaultValues: undefined,
51
+ disabled: false,
52
+ }, (props, { element, dispatch, flag, expose }) => {
53
+ // Pattern C: the Form component owns the value store + validation and hands up a
54
+ // controller; the facade captures it and exposes delegating instance methods.
55
+ let controller: FormController | undefined;
56
+ expose({
57
+ /** Focus the first control, or the first INVALID control after a failed validation. */
58
+ focus: (options?: FocusOptions) => controller?.focus(options),
59
+ /** Validate + submit programmatically — focus the first invalid field on failure,
60
+ * else emit the `submit` CardEvent and resolve. Named `send`, not `submit`. */
61
+ send: () => controller?.send(),
62
+ /** Run client-side validation now and return `{ valid, errors? }` WITHOUT submitting. */
63
+ validate: () => controller?.validate() ?? { valid: false },
64
+ /** Re-seed the form from each field's `default` and clear errors. */
65
+ reset: () => controller?.reset(),
66
+ /** Trigger the dismiss path (emit `dismiss` + collapse to the re-openable stub). */
67
+ dismiss: () => controller?.dismiss(),
68
+ /** Re-open a dismissed card from its stub (emit `reopen`). */
69
+ reopen: () => controller?.reopen(),
70
+ });
71
+
72
+ return (
73
+ <Form
74
+ data={props.data as FormDefinition | undefined}
75
+ cardId={props.cardId ?? (element.id || 'kai-form')}
76
+ heading={props.heading}
77
+ resolution={props.resolution as CardResolution | undefined}
78
+ values={props.values as Record<string, unknown> | undefined}
79
+ defaultValues={props.defaultValues as Record<string, unknown> | undefined}
80
+ disabled={flag('disabled')}
81
+ onValuesChange={(payload) => dispatch('kai-values-change', payload)}
82
+ controllerRef={(c) => (controller = c)}
83
+ hostElement={element}
84
+ />
85
+ );
86
+ });
@@ -0,0 +1,80 @@
1
+ import { type Placement } from '@floating-ui/dom';
2
+ import { HoverCardRoot, HoverCardTrigger, HoverCardContent, type HoverCardController } from '../ui/hover-card';
3
+ import { defineWebComponent } from './define';
4
+ import { wireDisclosure } from './disclosure';
5
+
6
+ interface Props extends Record<string, unknown> {
7
+ /** Delay (ms) before the card opens on hover. Defaults to 0 (focus opens it
8
+ * immediately too). */
9
+ openDelay?: number;
10
+ /** Delay (ms) before it closes after the pointer leaves. Defaults to 300. */
11
+ closeDelay?: number;
12
+ /** Preferred placement: `'top' | 'bottom' | 'left' | 'right'` (+ optional
13
+ * `-start`/`-end`). Defaults to `'bottom'`; flips to stay in view. */
14
+ placement?: string;
15
+ /** Drive/observe open state (Shoelace-style: settable + reflected to the `open`
16
+ * attribute, the element still self-manages on hover). Set `el.open = true`,
17
+ * or `<kai-hover-card open>`; listen for `kai-open-change`. */
18
+ open?: boolean;
19
+ /** Initial open state on mount (uncontrolled seed). */
20
+ defaultOpen?: boolean;
21
+ /** Suppress the hover behavior entirely without unmounting. */
22
+ disabled?: boolean;
23
+ }
24
+
25
+ /** Events fired by `<kai-hover-card>`. */
26
+ interface Events {
27
+ /** The card opened or closed (by hover/focus, outside-click, or a method). */
28
+ 'kai-open-change': { open: boolean };
29
+ }
30
+
31
+ /**
32
+ * `<kai-hover-card>` — reveals RICH content on hover/focus of a trigger (the
33
+ * markup-carrying sibling of the text-only `<kai-tooltip>`). Put the trigger as
34
+ * default light-DOM content and the card body in `slot="card"`. The card is
35
+ * portaled + positioned inside the shadow root, with a transparent hover bridge
36
+ * so the pointer can travel into it.
37
+ *
38
+ * ```html
39
+ * <kai-hover-card>
40
+ * <a href="#">@acme</a>
41
+ * <div slot="card">
42
+ * <strong>Acme Corp</strong>
43
+ * <p>Workspace · 24 members</p>
44
+ * </div>
45
+ * </kai-hover-card>
46
+ * ```
47
+ */
48
+ defineWebComponent<Props, Events>('kai-hover-card', {
49
+ openDelay: undefined,
50
+ closeDelay: undefined,
51
+ placement: undefined,
52
+ open: undefined,
53
+ defaultOpen: undefined,
54
+ disabled: undefined,
55
+ }, (props, ctx) => {
56
+ const { flag } = ctx;
57
+ let api: HoverCardController | undefined;
58
+
59
+ // The standard overlay surface: settable+reflecting `open`, kai-open-change,
60
+ // show/hide/toggle, disabled-gating. See ./disclosure.
61
+ wireDisclosure(ctx, () => api, () => props.open);
62
+
63
+ return (
64
+ <>
65
+ <style>{':host{display:inline-block}'}</style>
66
+ <HoverCardRoot
67
+ openDelay={props.openDelay != null ? Number(props.openDelay) : undefined}
68
+ closeDelay={props.closeDelay != null ? Number(props.closeDelay) : undefined}
69
+ defaultOpen={flag('defaultOpen')}
70
+ disabled={flag('disabled')}
71
+ controllerRef={(a) => (api = a)}
72
+ >
73
+ <HoverCardTrigger><slot /></HoverCardTrigger>
74
+ <HoverCardContent placement={(props.placement as Placement | undefined) ?? undefined}>
75
+ <slot name="card" />
76
+ </HoverCardContent>
77
+ </HoverCardRoot>
78
+ </>
79
+ );
80
+ });
@@ -0,0 +1,48 @@
1
+ [
2
+ "archive",
3
+ "arrow-left",
4
+ "arrow-up",
5
+ "audio-lines",
6
+ "book-open",
7
+ "bookmark",
8
+ "box",
9
+ "briefcase",
10
+ "chevron-down",
11
+ "chevron-left",
12
+ "circle",
13
+ "clock",
14
+ "code",
15
+ "copy",
16
+ "ellipsis",
17
+ "external-link",
18
+ "file-text",
19
+ "flag",
20
+ "folder",
21
+ "git-branch",
22
+ "git-pull-request",
23
+ "github",
24
+ "globe",
25
+ "home",
26
+ "image",
27
+ "list-filter",
28
+ "lock",
29
+ "message-circle",
30
+ "message-square",
31
+ "mic",
32
+ "monitor",
33
+ "more-horizontal",
34
+ "panel-left",
35
+ "paperclip",
36
+ "pencil",
37
+ "plus",
38
+ "rotate-cw",
39
+ "search",
40
+ "settings",
41
+ "share",
42
+ "sliders-horizontal",
43
+ "smile",
44
+ "sparkles",
45
+ "square-pen",
46
+ "workflow",
47
+ "x"
48
+ ]
@@ -0,0 +1,41 @@
1
+ import { renderIcon } from '../ui/icon';
2
+ import { cn } from '../utils/cn';
3
+ import { defineWebComponent } from './define';
4
+
5
+ const SIZE: Record<string, string> = { sm: 'size-3.5', md: 'size-4', lg: 'size-5' };
6
+
7
+ interface Props extends Record<string, unknown> {
8
+ /** A curated icon name (e.g. `"mic"`, `"globe"`), an image URL/data-URI, or
9
+ * plain text. */
10
+ name?: string;
11
+ /** Size token: `sm` | `md` (default) | `lg`. */
12
+ size?: 'sm' | 'md' | 'lg';
13
+ }
14
+
15
+ /**
16
+ * `<kai-icon>` — render one of the kit's curated icons (inline SVG) in your own
17
+ * markup, so surrounding UI can match the kit without pulling in an icon library.
18
+ * `name` also accepts a URL/data-URI or text. Renders in the theme's foreground by
19
+ * default; recolor with `kai-icon::part(icon){ color: … }`.
20
+ *
21
+ * Scope: the kit's small, *curated* icon set — not a general icon library. For
22
+ * anything outside it, drop your own inline SVG into an element's `icon` slot.
23
+ *
24
+ * ```html
25
+ * <kai-icon name="globe"></kai-icon>
26
+ * <kai-icon name="sparkles" size="lg"></kai-icon>
27
+ * ```
28
+ */
29
+ defineWebComponent<Props>('kai-icon', {
30
+ name: '',
31
+ size: 'md',
32
+ }, (props) => (
33
+ <>
34
+ {/* Base sets `:host{display:block}`; an inline icon must flow with surrounding
35
+ text (and not force a line break), so inline-flex like kai-button. */}
36
+ <style>{':host{display:inline-flex}'}</style>
37
+ <span part="icon" class={cn('inline-flex shrink-0', SIZE[props.size ?? 'md'] ?? SIZE.md)}>
38
+ {renderIcon(props.name, { class: 'size-full', imgClass: 'size-full', spanClass: 'size-full' })}
39
+ </span>
40
+ </>
41
+ ));
@@ -0,0 +1,203 @@
1
+ import { createEffect, createSignal, onCleanup, onMount, untrack } from 'solid-js';
2
+ import { defineWebComponent } from './define';
3
+ import { Input, type InputProps } from '../ui/input';
4
+
5
+ interface Props extends Record<string, unknown> {
6
+ /** Native input type: `text` (default) · `email` · `url` · `search` · `tel` ·
7
+ * `password` · `number`. Single-line only. */
8
+ type?: string;
9
+ /** Controlled value — settable and reflected to the `value` attribute. `el.value
10
+ * = 'hi'` drives it (no event); typing updates it and fires `kai-input`. Read
11
+ * `el.value` for live state. */
12
+ value?: string;
13
+ /** Placeholder shown when empty. */
14
+ placeholder?: string;
15
+ /** Field label, linked to the input. */
16
+ label?: string;
17
+ /** Helper text below the control. */
18
+ hint?: string;
19
+ /** Error text; flips the field invalid (`aria-invalid` + destructive border). */
20
+ error?: string;
21
+ /** Control density: `sm` or `md`. Defaults to `md`. */
22
+ size?: 'sm' | 'md';
23
+ /** Disable interaction. */
24
+ disabled?: boolean;
25
+ /** Make the input read-only. */
26
+ readonly?: boolean;
27
+ /** Mark the input required. */
28
+ required?: boolean;
29
+ /** Force the invalid state without an `error` string. */
30
+ invalid?: boolean;
31
+ /** Form-control name. */
32
+ name?: string;
33
+ /** Autofill hint forwarded to the inner input (e.g. `email`, `current-password`). */
34
+ autocomplete?: string;
35
+ /** Virtual-keyboard hint forwarded to the inner input (e.g. `numeric`, `email`). */
36
+ inputmode?: string;
37
+ // NOTE: `autocapitalize` is forwarded too, but NOT as a declared prop — see the
38
+ // attribute read in the facade body (it is a global reflected HTMLElement IDL
39
+ // attribute and would break the element constructor as a component-register prop).
40
+ }
41
+
42
+ /** Events fired by `<kai-input>`. */
43
+ interface Events {
44
+ /** The value changed per keystroke. */
45
+ 'kai-input': { value: string };
46
+ /** The value was committed (blur). */
47
+ 'kai-change': { value: string };
48
+ }
49
+
50
+ /** Named slots whose occupancy gates an affix. An empty `<slot>` is always a
51
+ * truthy node, so the facade tracks which are actually filled and only hands a
52
+ * `<slot>` to the primitive when content is assigned — otherwise the primitive
53
+ * would switch to the affix-row layout for an empty slot. */
54
+ const SLOT_NAMES = ['leading', 'trailing'] as const;
55
+ type SlotName = (typeof SLOT_NAMES)[number];
56
+
57
+ /**
58
+ * `<kai-input>` — the kit's single-line text field. Drive/read the value with the
59
+ * `value` property (settable + reflected to the `value` attribute, so
60
+ * `:host([value])` and `el.value` see live state); listen for `kai-input` (per
61
+ * keystroke) and `kai-change` (commit/blur). A `label`, `hint`, and `error` wrap
62
+ * the control; `leading`/`trailing` slots take an icon, unit, or inline button.
63
+ *
64
+ * ```html
65
+ * <kai-input label="Workspace" placeholder="Acme Inc."></kai-input>
66
+ * <script type="module">
67
+ * import '@kitn.ai/ui/elements';
68
+ * const field = document.querySelector('kai-input');
69
+ * field.addEventListener('kai-input', (e) => console.log(e.detail.value));
70
+ * field.value = 'Acme'; // drive it (no event — the host already knows)
71
+ * field.focus(); // focus the inner input
72
+ * </script>
73
+ * ```
74
+ *
75
+ * Methods: `focus()`, `select()`, `clear()`. Restyle via `::part(field)`,
76
+ * `::part(input)`, `::part(label)`, `::part(hint)`.
77
+ */
78
+ defineWebComponent<Props, Events>('kai-input', {
79
+ type: 'text',
80
+ value: undefined,
81
+ placeholder: undefined,
82
+ label: undefined,
83
+ hint: undefined,
84
+ error: undefined,
85
+ size: 'md',
86
+ disabled: undefined,
87
+ readonly: undefined,
88
+ required: undefined,
89
+ invalid: undefined,
90
+ name: undefined,
91
+ autocomplete: undefined,
92
+ inputmode: undefined,
93
+ }, (props, ctx) => {
94
+ const { element, dispatch, flag, expose } = ctx;
95
+
96
+ // Lift the value into the facade and drive Input CONTROLLED so the host can read
97
+ // it (`el.value` / `:host([value])`) and set it after mount. Seed from the
98
+ // `value` property/attribute present on mount.
99
+ const [value, setValue] = createSignal(
100
+ (props.value as string | undefined) ?? element.getAttribute('value') ?? '',
101
+ );
102
+
103
+ // Coerce any value coming through the `value` setter (a JS assignment, or the
104
+ // write-back from `attributeChangedCallback`) to a string — falling back to the
105
+ // live attribute when nullish so the reflect write-back equals the signal and
106
+ // the equality guards absorb it (no attr⇄prop feedback loop; mirrors kai-segmented).
107
+ const coerce = (v: unknown): string =>
108
+ v == null ? (element.getAttribute('value') ?? '') : String(v);
109
+
110
+ // Set the value WITHOUT firing an event (programmatic / reflect write-back).
111
+ const setQuiet = (next: string) => { if (untrack(value) !== next) setValue(next); };
112
+
113
+ // Override `value` so reads return LIVE state and host writes (`el.value = …`)
114
+ // drive it WITHOUT firing events — distinct from the typing path.
115
+ Object.defineProperty(element, 'value', {
116
+ get: () => value(),
117
+ set: (v: unknown) => setQuiet(coerce(v)),
118
+ configurable: true,
119
+ enumerable: true,
120
+ });
121
+
122
+ // Reflect internal value → the `[value]` host attribute (for `:host([value])`).
123
+ // The guard against the live attribute keeps the write-back the reflect triggers
124
+ // (attributeChangedCallback → setter) from looping.
125
+ createEffect(() => {
126
+ const v = value();
127
+ if (v) {
128
+ if (element.getAttribute('value') !== v) element.setAttribute('value', v);
129
+ } else if (element.hasAttribute('value')) {
130
+ element.removeAttribute('value');
131
+ }
132
+ });
133
+
134
+ // `autocapitalize` is forwarded by reading the host attribute rather than as a
135
+ // declared prop: it is a global reflected HTMLElement IDL attribute (lowercase,
136
+ // like the reserved `lang`/`title`), so component-register's constructor
137
+ // `this.autocapitalize = undefined` would reflect an attribute and throw
138
+ // "must not have attributes". Seeded now; kept in sync by the observer in onMount.
139
+ const [autocapitalize, setAutocapitalize] = createSignal<string | undefined>(
140
+ element.getAttribute('autocapitalize') ?? undefined,
141
+ );
142
+
143
+ // Track which affix slots are filled; re-read on child mutations so late/streamed
144
+ // content lights up its affix. An empty slot is never passed to the primitive.
145
+ const [filled, setFilled] = createSignal<Record<SlotName, boolean>>({ leading: false, trailing: false });
146
+ onMount(() => {
147
+ const read = () => {
148
+ const next = {} as Record<SlotName, boolean>;
149
+ for (const name of SLOT_NAMES) next[name] = !!element.querySelector(`:scope > [slot="${name}"]`);
150
+ setFilled(next);
151
+ };
152
+ read();
153
+ const observer = new MutationObserver(read);
154
+ observer.observe(element, { childList: true, subtree: false });
155
+ onCleanup(() => observer.disconnect());
156
+
157
+ // Keep the forwarded `autocapitalize` in sync with the host attribute.
158
+ const syncAutocapitalize = () => setAutocapitalize(element.getAttribute('autocapitalize') ?? undefined);
159
+ syncAutocapitalize();
160
+ const attrObserver = new MutationObserver(syncAutocapitalize);
161
+ attrObserver.observe(element, { attributes: true, attributeFilter: ['autocapitalize'] });
162
+ onCleanup(() => attrObserver.disconnect());
163
+ });
164
+ const region = (name: SlotName) => (filled()[name] ? <slot name={name} /> : undefined);
165
+
166
+ const innerInput = () => element.shadowRoot?.querySelector<HTMLInputElement>('input') ?? null;
167
+
168
+ expose({
169
+ /** Focus the inner input (the host can't reach into the shadow root). */
170
+ focus: (options?: FocusOptions) => innerInput()?.focus(options),
171
+ /** Select the inner input's text. */
172
+ select: () => innerInput()?.select(),
173
+ /** Empty the value and fire `kai-change` with `''`. */
174
+ clear: () => { setValue(''); dispatch('kai-change', { value: '' }); },
175
+ });
176
+
177
+ return (
178
+ <>
179
+ <style>{':host{display:block}'}</style>
180
+ <Input
181
+ type={(props.type as string) ?? 'text'}
182
+ value={value()}
183
+ placeholder={props.placeholder as string | undefined}
184
+ label={props.label as string | undefined}
185
+ hint={props.hint as string | undefined}
186
+ error={props.error as string | undefined}
187
+ size={(props.size as 'sm' | 'md' | undefined) ?? 'md'}
188
+ invalid={flag('invalid')}
189
+ disabled={flag('disabled')}
190
+ readonly={flag('readonly')}
191
+ required={flag('required')}
192
+ name={props.name as string | undefined}
193
+ autocomplete={props.autocomplete as InputProps['autocomplete']}
194
+ inputmode={props.inputmode as InputProps['inputmode']}
195
+ autocapitalize={autocapitalize() as InputProps['autocapitalize']}
196
+ leading={region('leading')}
197
+ trailing={region('trailing')}
198
+ onValueInput={(v) => { setValue(v); dispatch('kai-input', { value: v }); }}
199
+ onValueChange={(v) => { setQuiet(v); dispatch('kai-change', { value: v }); }}
200
+ />
201
+ </>
202
+ );
203
+ });
@@ -0,0 +1,45 @@
1
+ import { defineWebComponent } from './define';
2
+ import { Kbd, type KbdPlatform } from '../ui/kbd';
3
+
4
+ interface Props extends Record<string, unknown> {
5
+ /** Shortcut spec — tokens joined by `+` (e.g. `Mod+Shift+K`). Omit it to show
6
+ * default-slot content instead. Display only; the element does not bind keys. */
7
+ keys?: string;
8
+ /** `mac` uses ⌘/⌥, `other` uses Ctrl. `auto` (default) sniffs the OS. */
9
+ platform?: KbdPlatform;
10
+ /** Cap size: `sm` or `md`. Defaults to `md`. */
11
+ size?: 'sm' | 'md';
12
+ }
13
+
14
+ /**
15
+ * `<kai-kbd>` — a keyboard-shortcut display. Feed it `keys` (tokens joined by
16
+ * `+`) and it renders one inset cap per token, mapping each to a platform glyph
17
+ * (`Mod` → ⌘ on mac else Ctrl, `Shift` → ⇧, `ArrowUp` → ↑, `Enter` → ⏎, …).
18
+ * Display only — it does not bind keys.
19
+ *
20
+ * ```html
21
+ * <kai-kbd keys="Mod+K"></kai-kbd>
22
+ * <kai-kbd keys="Mod+Shift+ArrowUp" platform="mac"></kai-kbd>
23
+ * <kai-kbd>Esc</kai-kbd> <!-- omit keys to show your own content -->
24
+ * ```
25
+ *
26
+ * `platform="auto"` (default) sniffs the OS for ⌘ vs Ctrl. Restyle the caps via
27
+ * `::part(key)` and the gaps via `::part(separator)`.
28
+ */
29
+ defineWebComponent<Props>('kai-kbd', {
30
+ keys: undefined,
31
+ platform: 'auto',
32
+ size: 'md',
33
+ }, (props) => (
34
+ <>
35
+ {/* Base sets `:host{display:block}`; a shortcut hint flows inline like a chip. */}
36
+ <style>{':host{display:inline-flex}'}</style>
37
+ <Kbd
38
+ keys={props.keys as string | undefined}
39
+ platform={(props.platform as KbdPlatform) ?? 'auto'}
40
+ size={(props.size as 'sm' | 'md') ?? 'md'}
41
+ >
42
+ <slot />
43
+ </Kbd>
44
+ </>
45
+ ));