@kitn.ai/ui 0.14.1

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 (370) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +394 -0
  3. package/dist/bash-InADTalH.js +1 -0
  4. package/dist/core-AYMC6_lb.js +12 -0
  5. package/dist/css-M7EaDHN_.js +1 -0
  6. package/dist/custom-elements.json +4739 -0
  7. package/dist/engine-javascript-vq0WuIJl.js +141 -0
  8. package/dist/github-dark-dimmed-DUshB20C.js +1 -0
  9. package/dist/github-light-JYsPkUQd.js +1 -0
  10. package/dist/host-embed.d.ts +33 -0
  11. package/dist/html-CPZ3oZQ7.js +1 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/javascript-C25yR2R2.js +1 -0
  14. package/dist/json-DxJze_jm.js +1 -0
  15. package/dist/kitn-chat-provider.d.ts +2 -0
  16. package/dist/kitn-chat-provider.es.js +240 -0
  17. package/dist/kitn-chat.es.js +77 -0
  18. package/dist/llms/llms-full.txt +1018 -0
  19. package/dist/llms/llms.txt +104 -0
  20. package/dist/origin.d.ts +5 -0
  21. package/dist/provider-runtime.d.ts +27 -0
  22. package/dist/schemas/card-envelope.schema.json +14 -0
  23. package/dist/schemas/card-event.schema.json +12 -0
  24. package/dist/schemas/choice.schema.json +70 -0
  25. package/dist/schemas/confirm.schema.json +65 -0
  26. package/dist/schemas/embed.schema.json +65 -0
  27. package/dist/schemas/form.result.schema.json +7 -0
  28. package/dist/schemas/form.schema.json +33 -0
  29. package/dist/schemas/link.schema.json +56 -0
  30. package/dist/schemas/tasks.result.schema.json +16 -0
  31. package/dist/schemas/tasks.schema.json +78 -0
  32. package/dist/svelte--5p79yCD.js +1 -0
  33. package/dist/theme.tokens.css +176 -0
  34. package/dist/tsx-B8rCNbgL.js +1 -0
  35. package/dist/typescript-RycA9KXf.js +1 -0
  36. package/dist/validate.d.ts +4 -0
  37. package/dist/version.d.ts +4 -0
  38. package/dist/vue-BmIZj4XD.js +1 -0
  39. package/dist/wire.d.ts +53 -0
  40. package/frameworks/react/index.tsx +948 -0
  41. package/frameworks/react/runtime.tsx +94 -0
  42. package/llms-full.txt +1018 -0
  43. package/llms.txt +104 -0
  44. package/package.json +141 -0
  45. package/src/components/artifact.stories.tsx +138 -0
  46. package/src/components/artifact.tsx +743 -0
  47. package/src/components/attachments.stories.tsx +303 -0
  48. package/src/components/attachments.test.tsx +64 -0
  49. package/src/components/attachments.tsx +399 -0
  50. package/src/components/card-fallback.tsx +28 -0
  51. package/src/components/card-renderer.tsx +52 -0
  52. package/src/components/card.tsx +110 -0
  53. package/src/components/chain-of-thought.stories.tsx +211 -0
  54. package/src/components/chain-of-thought.tsx +139 -0
  55. package/src/components/chat-container.stories.tsx +187 -0
  56. package/src/components/chat-container.tsx +82 -0
  57. package/src/components/chat-scope-picker.tsx +47 -0
  58. package/src/components/chat-thread.test.tsx +58 -0
  59. package/src/components/chat-thread.tsx +249 -0
  60. package/src/components/checkpoint.stories.tsx +102 -0
  61. package/src/components/checkpoint.tsx +88 -0
  62. package/src/components/choice-card.tsx +569 -0
  63. package/src/components/code-block.stories.tsx +150 -0
  64. package/src/components/code-block.tsx +105 -0
  65. package/src/components/component-meta.json +3735 -0
  66. package/src/components/confirm-card.stories.tsx +74 -0
  67. package/src/components/confirm-card.tsx +315 -0
  68. package/src/components/context.stories.tsx +229 -0
  69. package/src/components/context.test.tsx +133 -0
  70. package/src/components/context.tsx +363 -0
  71. package/src/components/conversation-item.stories.tsx +125 -0
  72. package/src/components/conversation-item.tsx +16 -0
  73. package/src/components/conversation-list.stories.tsx +133 -0
  74. package/src/components/conversation-list.tsx +101 -0
  75. package/src/components/default-input.test.tsx +111 -0
  76. package/src/components/embed.tsx +196 -0
  77. package/src/components/empty.stories.tsx +434 -0
  78. package/src/components/empty.tsx +166 -0
  79. package/src/components/feedback-bar.stories.tsx +138 -0
  80. package/src/components/feedback-bar.test.tsx +103 -0
  81. package/src/components/feedback-bar.tsx +166 -0
  82. package/src/components/file-tree.stories.tsx +73 -0
  83. package/src/components/file-tree.tsx +383 -0
  84. package/src/components/file-upload.stories.tsx +156 -0
  85. package/src/components/file-upload.tsx +161 -0
  86. package/src/components/form-widgets.tsx +461 -0
  87. package/src/components/form.tsx +873 -0
  88. package/src/components/image.stories.tsx +89 -0
  89. package/src/components/image.tsx +67 -0
  90. package/src/components/link-preview.tsx +194 -0
  91. package/src/components/loader.stories.tsx +181 -0
  92. package/src/components/loader.tsx +333 -0
  93. package/src/components/markdown.stories.tsx +180 -0
  94. package/src/components/markdown.tsx +81 -0
  95. package/src/components/message-action-bar.test.tsx +128 -0
  96. package/src/components/message-narrow.stories.tsx +329 -0
  97. package/src/components/message-skills.stories.tsx +211 -0
  98. package/src/components/message-skills.tsx +36 -0
  99. package/src/components/message.stories.tsx +281 -0
  100. package/src/components/message.tsx +227 -0
  101. package/src/components/model-switcher.stories.tsx +123 -0
  102. package/src/components/model-switcher.test.tsx +65 -0
  103. package/src/components/model-switcher.tsx +87 -0
  104. package/src/components/prompt-input.stories.tsx +222 -0
  105. package/src/components/prompt-input.tsx +211 -0
  106. package/src/components/prompt-suggestion.stories.tsx +142 -0
  107. package/src/components/prompt-suggestion.tsx +115 -0
  108. package/src/components/reasoning.stories.tsx +140 -0
  109. package/src/components/reasoning.tsx +156 -0
  110. package/src/components/resizable.test.tsx +226 -0
  111. package/src/components/response-stream.tsx +103 -0
  112. package/src/components/scroll-button.stories.tsx +100 -0
  113. package/src/components/scroll-button.tsx +34 -0
  114. package/src/components/slash-command.stories.tsx +163 -0
  115. package/src/components/slash-command.tsx +232 -0
  116. package/src/components/source-list.test.tsx +152 -0
  117. package/src/components/source.stories.tsx +124 -0
  118. package/src/components/source.tsx +129 -0
  119. package/src/components/tasks-card.stories.tsx +78 -0
  120. package/src/components/tasks-card.tsx +432 -0
  121. package/src/components/text-shimmer.stories.tsx +87 -0
  122. package/src/components/text-shimmer.tsx +37 -0
  123. package/src/components/thinking-bar.stories.tsx +87 -0
  124. package/src/components/thinking-bar.tsx +50 -0
  125. package/src/components/tool.stories.tsx +153 -0
  126. package/src/components/tool.tsx +184 -0
  127. package/src/components/use-card-resolution.ts +28 -0
  128. package/src/components/voice-input.stories.tsx +83 -0
  129. package/src/components/voice-input.tsx +107 -0
  130. package/src/elements/artifact.stories.tsx +506 -0
  131. package/src/elements/artifact.tsx +137 -0
  132. package/src/elements/attachments.stories.tsx +190 -0
  133. package/src/elements/attachments.tsx +136 -0
  134. package/src/elements/card.stories.tsx +113 -0
  135. package/src/elements/card.tsx +40 -0
  136. package/src/elements/cards.stories.tsx +59 -0
  137. package/src/elements/cards.tsx +97 -0
  138. package/src/elements/catalog.stories.tsx +491 -0
  139. package/src/elements/chain-of-thought.declarative.test.tsx +153 -0
  140. package/src/elements/chain-of-thought.stories.tsx +113 -0
  141. package/src/elements/chain-of-thought.tsx +92 -0
  142. package/src/elements/chat-scope-picker.stories.tsx +73 -0
  143. package/src/elements/chat-scope-picker.tsx +36 -0
  144. package/src/elements/chat-types.ts +42 -0
  145. package/src/elements/chat-workspace.stories.tsx +288 -0
  146. package/src/elements/chat-workspace.tsx +161 -0
  147. package/src/elements/chat.stories.tsx +151 -0
  148. package/src/elements/chat.tsx +80 -0
  149. package/src/elements/checkpoint.stories.tsx +72 -0
  150. package/src/elements/checkpoint.tsx +47 -0
  151. package/src/elements/choice.stories.tsx +240 -0
  152. package/src/elements/choice.tsx +48 -0
  153. package/src/elements/code-block.stories.tsx +83 -0
  154. package/src/elements/code-block.tsx +42 -0
  155. package/src/elements/compiled.css +2 -0
  156. package/src/elements/composed-shell.stories.tsx +316 -0
  157. package/src/elements/confirm-card.stories.tsx +227 -0
  158. package/src/elements/confirm-card.tsx +51 -0
  159. package/src/elements/context-meter.stories.tsx +151 -0
  160. package/src/elements/context-meter.tsx +121 -0
  161. package/src/elements/conversation-list.declarative.test.tsx +137 -0
  162. package/src/elements/conversation-list.stories.tsx +243 -0
  163. package/src/elements/conversation-list.tsx +80 -0
  164. package/src/elements/css.ts +5 -0
  165. package/src/elements/default-input.tsx +247 -0
  166. package/src/elements/define.tsx +171 -0
  167. package/src/elements/element-meta.json +3314 -0
  168. package/src/elements/element-types.d.ts +710 -0
  169. package/src/elements/embed.stories.tsx +213 -0
  170. package/src/elements/embed.tsx +35 -0
  171. package/src/elements/empty.stories.tsx +111 -0
  172. package/src/elements/empty.tsx +29 -0
  173. package/src/elements/feedback-bar.stories.tsx +114 -0
  174. package/src/elements/feedback-bar.tsx +61 -0
  175. package/src/elements/file-tree.stories.tsx +134 -0
  176. package/src/elements/file-tree.tsx +52 -0
  177. package/src/elements/file-upload.stories.tsx +82 -0
  178. package/src/elements/file-upload.tsx +44 -0
  179. package/src/elements/form.stories.tsx +248 -0
  180. package/src/elements/form.tsx +43 -0
  181. package/src/elements/framework-usage.json +563 -0
  182. package/src/elements/image.stories.tsx +71 -0
  183. package/src/elements/image.tsx +32 -0
  184. package/src/elements/link-preview.stories.tsx +209 -0
  185. package/src/elements/link-preview.tsx +34 -0
  186. package/src/elements/loader.stories.tsx +88 -0
  187. package/src/elements/loader.tsx +25 -0
  188. package/src/elements/markdown.stories.tsx +76 -0
  189. package/src/elements/markdown.tsx +38 -0
  190. package/src/elements/message-skills.declarative.test.tsx +104 -0
  191. package/src/elements/message-skills.stories.tsx +114 -0
  192. package/src/elements/message-skills.tsx +85 -0
  193. package/src/elements/message.stories.tsx +218 -0
  194. package/src/elements/message.tsx +162 -0
  195. package/src/elements/model-switcher.declarative.test.tsx +130 -0
  196. package/src/elements/model-switcher.stories.tsx +198 -0
  197. package/src/elements/model-switcher.tsx +93 -0
  198. package/src/elements/popover.stories.tsx +80 -0
  199. package/src/elements/popover.tsx +59 -0
  200. package/src/elements/prompt-input-slash-command.test.tsx +128 -0
  201. package/src/elements/prompt-input-stoppable.test.tsx +88 -0
  202. package/src/elements/prompt-input-toolbar-actions.test.tsx +120 -0
  203. package/src/elements/prompt-input.stories.tsx +331 -0
  204. package/src/elements/prompt-input.tsx +185 -0
  205. package/src/elements/prompt-suggestions.declarative.test.tsx +164 -0
  206. package/src/elements/prompt-suggestions.stories.tsx +213 -0
  207. package/src/elements/prompt-suggestions.tsx +94 -0
  208. package/src/elements/reasoning.stories.tsx +77 -0
  209. package/src/elements/reasoning.tsx +50 -0
  210. package/src/elements/register.ts +56 -0
  211. package/src/elements/remote.stories.tsx +314 -0
  212. package/src/elements/remote.tsx +221 -0
  213. package/src/elements/resizable.d.ts +27 -0
  214. package/src/elements/resizable.stories.tsx +426 -0
  215. package/src/elements/resizable.tsx +553 -0
  216. package/src/elements/response-stream.stories.tsx +79 -0
  217. package/src/elements/response-stream.tsx +40 -0
  218. package/src/elements/scroll-button.stories.tsx +202 -0
  219. package/src/elements/scroll-button.test.tsx +148 -0
  220. package/src/elements/scroll-button.tsx +126 -0
  221. package/src/elements/source-list.stories.tsx +143 -0
  222. package/src/elements/source.stories.tsx +88 -0
  223. package/src/elements/source.tsx +120 -0
  224. package/src/elements/styles.css +199 -0
  225. package/src/elements/switch.stories.tsx +56 -0
  226. package/src/elements/switch.tsx +43 -0
  227. package/src/elements/tasks.stories.tsx +237 -0
  228. package/src/elements/tasks.tsx +46 -0
  229. package/src/elements/text-shimmer.stories.tsx +64 -0
  230. package/src/elements/text-shimmer.tsx +28 -0
  231. package/src/elements/thinking-bar.stories.tsx +72 -0
  232. package/src/elements/thinking-bar.tsx +34 -0
  233. package/src/elements/tool.stories.tsx +89 -0
  234. package/src/elements/tool.tsx +23 -0
  235. package/src/elements/voice-input.stories.tsx +88 -0
  236. package/src/elements/voice-input.tsx +41 -0
  237. package/src/index.ts +253 -0
  238. package/src/primitives/card-contract.ts +71 -0
  239. package/src/primitives/card-host.tsx +35 -0
  240. package/src/primitives/card-registry.tsx +67 -0
  241. package/src/primitives/card-resolution.ts +36 -0
  242. package/src/primitives/card-routing.ts +79 -0
  243. package/src/primitives/card-schemas/card-envelope.schema.json +14 -0
  244. package/src/primitives/card-schemas/card-event.schema.json +12 -0
  245. package/src/primitives/card-schemas/choice.schema.json +70 -0
  246. package/src/primitives/card-schemas/confirm.schema.json +65 -0
  247. package/src/primitives/card-schemas/embed.schema.json +65 -0
  248. package/src/primitives/card-schemas/form.result.schema.json +7 -0
  249. package/src/primitives/card-schemas/form.schema.json +33 -0
  250. package/src/primitives/card-schemas/link.schema.json +56 -0
  251. package/src/primitives/card-schemas/tasks.result.schema.json +16 -0
  252. package/src/primitives/card-schemas/tasks.schema.json +78 -0
  253. package/src/primitives/card-validate.ts +95 -0
  254. package/src/primitives/chat-config.tsx +76 -0
  255. package/src/primitives/controllable.test.ts +47 -0
  256. package/src/primitives/controllable.ts +21 -0
  257. package/src/primitives/embed-providers.ts +254 -0
  258. package/src/primitives/highlighter.ts +157 -0
  259. package/src/primitives/link-preview.ts +87 -0
  260. package/src/primitives/pdf-preview.ts +121 -0
  261. package/src/primitives/use-auto-resize.ts +31 -0
  262. package/src/primitives/use-resize-observer.ts +12 -0
  263. package/src/primitives/use-stick-to-bottom.ts +43 -0
  264. package/src/primitives/use-text-stream.ts +112 -0
  265. package/src/primitives/use-voice-recorder.ts +50 -0
  266. package/src/remote/host-embed.ts +345 -0
  267. package/src/remote/index.ts +2 -0
  268. package/src/remote/origin.ts +30 -0
  269. package/src/remote/provider-runtime.ts +259 -0
  270. package/src/remote/provider.ts +2 -0
  271. package/src/remote/validate.ts +22 -0
  272. package/src/remote/version.ts +12 -0
  273. package/src/remote/wire.ts +48 -0
  274. package/src/stories/chat-panel-layout.stories.tsx +145 -0
  275. package/src/stories/chat-scene.tsx +571 -0
  276. package/src/stories/checkpoint-restore.stories.tsx +256 -0
  277. package/src/stories/context-usage.stories.tsx +212 -0
  278. package/src/stories/conversation-with-reasoning.stories.tsx +182 -0
  279. package/src/stories/conversation-with-sources.stories.tsx +471 -0
  280. package/src/stories/docs/Accessibility.mdx +119 -0
  281. package/src/stories/docs/ChildElements.mdx +269 -0
  282. package/src/stories/docs/ForAIAgents.mdx +162 -0
  283. package/src/stories/docs/GettingStarted.mdx +65 -0
  284. package/src/stories/docs/Installation.mdx +83 -0
  285. package/src/stories/docs/Introduction.mdx +50 -0
  286. package/src/stories/docs/SolidJsAdvanced.mdx +17 -0
  287. package/src/stories/docs/Theming.mdx +85 -0
  288. package/src/stories/docs/element-controls.ts +121 -0
  289. package/src/stories/docs/frameworks/Angular.mdx +245 -0
  290. package/src/stories/docs/frameworks/Html.mdx +227 -0
  291. package/src/stories/docs/frameworks/Overview.mdx +47 -0
  292. package/src/stories/docs/frameworks/React.mdx +227 -0
  293. package/src/stories/docs/frameworks/Solid.mdx +173 -0
  294. package/src/stories/docs/frameworks/Svelte.mdx +194 -0
  295. package/src/stories/docs/frameworks/Vue.mdx +238 -0
  296. package/src/stories/docs/generative-ui-overview.mdx +186 -0
  297. package/src/stories/docs/recipes/SpeechToText.mdx +7 -0
  298. package/src/stories/docs/recipes/Streaming.mdx +68 -0
  299. package/src/stories/docs/recipes/TextToSpeech.mdx +35 -0
  300. package/src/stories/docs/theme-editor/canvas.tsx +32 -0
  301. package/src/stories/docs/theme-editor/inspector.tsx +66 -0
  302. package/src/stories/docs/theme-editor/presets.test.ts +32 -0
  303. package/src/stories/docs/theme-editor/presets.ts +64 -0
  304. package/src/stories/docs/theme-editor/theme-css.test.ts +19 -0
  305. package/src/stories/docs/theme-editor/theme-css.ts +15 -0
  306. package/src/stories/docs/theme-editor/theme-editor.tsx +146 -0
  307. package/src/stories/docs/theme-tokens.tsx +174 -0
  308. package/src/stories/examples/ChoosingComponents.mdx +106 -0
  309. package/src/stories/examples/sample-data.ts +79 -0
  310. package/src/stories/examples/usage/checkpoint-restore.ts +156 -0
  311. package/src/stories/examples/usage/context-usage.ts +591 -0
  312. package/src/stories/examples/usage/conversation-with-reasoning.ts +224 -0
  313. package/src/stories/examples/usage/conversation-with-sources.ts +589 -0
  314. package/src/stories/examples/usage/empty-state.ts +144 -0
  315. package/src/stories/examples/usage/full-chat-app.ts +277 -0
  316. package/src/stories/examples/usage/index.ts +63 -0
  317. package/src/stories/examples/usage/message-actions.ts +704 -0
  318. package/src/stories/examples/usage/pattern-centered-conversation.ts +446 -0
  319. package/src/stories/examples/usage/pattern-chat-panel-layout.ts +442 -0
  320. package/src/stories/examples/usage/pattern-docked-widget.ts +479 -0
  321. package/src/stories/examples/usage/prompt-input-variants.ts +1356 -0
  322. package/src/stories/examples/usage/streaming-response.ts +687 -0
  323. package/src/stories/examples/usage/types.ts +33 -0
  324. package/src/stories/full-chat.stories.tsx +18 -0
  325. package/src/stories/message-actions.stories.tsx +230 -0
  326. package/src/stories/pattern-centered-conversation.stories.tsx +93 -0
  327. package/src/stories/pattern-docked-widget.stories.tsx +93 -0
  328. package/src/stories/pattern-empty-state.stories.tsx +76 -0
  329. package/src/stories/prompt-input-variants.stories.tsx +456 -0
  330. package/src/stories/streaming-response.stories.tsx +438 -0
  331. package/src/stories/theme-editor.stories.tsx +16 -0
  332. package/src/stories/token-reference.stories.tsx +18 -0
  333. package/src/stories/typography.stories.tsx +78 -0
  334. package/src/types.ts +47 -0
  335. package/src/ui/action-icons.ts +52 -0
  336. package/src/ui/avatar.stories.tsx +103 -0
  337. package/src/ui/avatar.tsx +23 -0
  338. package/src/ui/badge.stories.tsx +86 -0
  339. package/src/ui/badge.tsx +21 -0
  340. package/src/ui/button.stories.tsx +145 -0
  341. package/src/ui/button.tsx +38 -0
  342. package/src/ui/collapsible.stories.tsx +69 -0
  343. package/src/ui/collapsible.tsx +125 -0
  344. package/src/ui/dropdown.stories.tsx +59 -0
  345. package/src/ui/dropdown.tsx +196 -0
  346. package/src/ui/hover-card.stories.tsx +77 -0
  347. package/src/ui/hover-card.test.tsx +30 -0
  348. package/src/ui/hover-card.tsx +172 -0
  349. package/src/ui/overlay.stories.tsx +115 -0
  350. package/src/ui/overlay.tsx +158 -0
  351. package/src/ui/popover.stories.tsx +81 -0
  352. package/src/ui/popover.test.tsx +99 -0
  353. package/src/ui/popover.tsx +92 -0
  354. package/src/ui/resizable.stories.tsx +236 -0
  355. package/src/ui/resizable.tsx +576 -0
  356. package/src/ui/scroll-area.stories.tsx +50 -0
  357. package/src/ui/scroll-area.tsx +15 -0
  358. package/src/ui/separator.stories.tsx +81 -0
  359. package/src/ui/separator.tsx +10 -0
  360. package/src/ui/skeleton.stories.tsx +337 -0
  361. package/src/ui/skeleton.tsx +16 -0
  362. package/src/ui/switch.stories.tsx +51 -0
  363. package/src/ui/switch.test.tsx +59 -0
  364. package/src/ui/switch.tsx +62 -0
  365. package/src/ui/textarea.stories.tsx +76 -0
  366. package/src/ui/textarea.tsx +21 -0
  367. package/src/ui/tooltip.stories.tsx +74 -0
  368. package/src/ui/tooltip.tsx +68 -0
  369. package/src/utils/cn.ts +24 -0
  370. package/theme.css +187 -0
@@ -0,0 +1,85 @@
1
+ import { Meta, Canvas } from '@storybook/addon-docs/blocks';
2
+ import * as TokenRef from '../token-reference.stories';
3
+
4
+ <Meta title="Theming/Overview" />
5
+
6
+ # Theming
7
+
8
+ The kit's appearance is driven entirely by **CSS custom properties** (`--color-*` design tokens) defined in `theme.css`. Override them to rebrand everything — buttons, bubbles, borders, the sidebar, code blocks — without touching component code.
9
+
10
+ ## Overriding tokens
11
+
12
+ Because inherited CSS pierces the Shadow DOM boundary, setting tokens on `:root` re-themes both the SolidJS components and the web components:
13
+
14
+ ```css
15
+ :root {
16
+ --color-background: #0f0f0f;
17
+ --color-foreground: #f5f5f5;
18
+ --color-primary: #7c3aed;
19
+ --color-primary-foreground: #ffffff;
20
+ --color-muted: #1e1e1e;
21
+ --color-border: #2a2a2a;
22
+ }
23
+ ```
24
+
25
+ Scope the same variables to a parent element instead of `:root` to theme just one subtree. The tokens follow the **shadcn/ui convention**: they're *semantic* (`--color-primary`, not `--color-blue`) and come in **`X` / `X-foreground` pairs** — a surface color and the text color that sits on it.
26
+
27
+ ## Live editor
28
+
29
+ Edit every token for **light and dark** modes and watch a real chat UI re-skin live — pick a preset, tweak swatches, then **Copy CSS** for a paste-ready `:root` + `.dark` block.
30
+
31
+ <a
32
+ href="?path=/story/theming-editor--editor"
33
+ style={{
34
+ display: 'inline-block',
35
+ background: 'var(--color-primary, #18181b)',
36
+ borderRadius: 'var(--radius-md, 0.5rem)',
37
+ padding: '0.4rem 0.85rem',
38
+ textDecoration: 'none',
39
+ }}
40
+ >
41
+ <span style={{
42
+ color: 'var(--color-primary-foreground, #fafafa)',
43
+ fontWeight: 600,
44
+ fontSize: '0.8125rem',
45
+ lineHeight: 1.3,
46
+ }}>Open the theme editor</span>
47
+ </a>
48
+
49
+ _(Opens full-screen — it needs more room than this docs column.)_
50
+
51
+ ## Token reference
52
+
53
+ A complete, auto-generated reference of every token you can override — generated live from the loaded CSS, so it never drifts from `theme.css`:
54
+
55
+ <Canvas of={TokenRef.TokenReference} />
56
+
57
+ ## Dark mode
58
+
59
+ The kit ships light and dark token sets. Toggle dark mode by adding the `dark` class to a root element (this Storybook's toolbar does exactly that):
60
+
61
+ ```js
62
+ document.documentElement.classList.toggle('dark');
63
+ ```
64
+
65
+ ## Appearance settings
66
+
67
+ `ChatConfig` (SolidJS) and matching properties on `<kai-chat>` control non-color appearance:
68
+
69
+ | Setting | Values | Purpose |
70
+ | --- | --- | --- |
71
+ | `proseSize` | `xs` · `sm` · `base` · `lg` | Text/markdown sizing |
72
+ | `codeTheme` | any Shiki theme name | Syntax-highlight theme for code blocks |
73
+ | `codeHighlight` | `true` / `false` | Turn code highlighting off entirely (renders plain text, loads no Shiki) |
74
+
75
+ ```tsx
76
+ <ChatConfig proseSize="base" codeTheme="github-dark-dimmed">
77
+ {/* ... */}
78
+ </ChatConfig>
79
+ ```
80
+
81
+ ```html
82
+ <kai-chat prose-size="base" code-theme="github-dark-dimmed"></kai-chat>
83
+ ```
84
+
85
+ That's the whole theming surface — tokens for color, `ChatConfig` for sizing and code. Everything else is encapsulated.
@@ -0,0 +1,121 @@
1
+ import meta from '../../elements/element-meta.json';
2
+
3
+ type Prop = { name: string; type: string; default?: string; scalar: boolean };
4
+ type ElementMeta = { tag: string; props: Prop[] };
5
+ const all = meta as unknown as ElementMeta[];
6
+
7
+ // A small, consistent pointer at the top of every Web Component's Docs tab,
8
+ // directing readers to the dedicated API tab (which holds the full generated
9
+ // spec). Keeps the Docs tab focused on examples while keeping the spec one click
10
+ // away — and discoverable, since everyone reads the description first.
11
+ const API_POINTER =
12
+ '> **Full API reference** — every property, event, default and token is on the **API** tab above.';
13
+
14
+ /**
15
+ * Build a Storybook `docs.description` from an element's intro paragraphs, with
16
+ * the API-tab pointer prepended. The generated spec itself lives in the **API**
17
+ * tab (see `.storybook/api-tab.tsx`), not inline here.
18
+ * (`tag` is kept in the signature so callers don't churn if we re-inline later.)
19
+ */
20
+ export function specDescription(_tag: string, paragraphs: string[]): { component: string } {
21
+ return { component: [API_POINTER, ...paragraphs].join('\n\n') };
22
+ }
23
+
24
+ // The Components/UI sibling of API_POINTER — same idea, component vocabulary
25
+ // (props/callbacks/slots rather than properties/events/attributes).
26
+ const COMPONENT_POINTER =
27
+ '> **Full API reference** — every prop, callback, slot and token is on the **API** tab above.';
28
+
29
+ /**
30
+ * Build a Storybook `docs.description` for a SolidJS/UI component story, with the
31
+ * API-tab pointer prepended. The generated spec (props/callbacks/slots/tokens)
32
+ * lives on the **API** tab (see `.storybook/api-tab.tsx`), from
33
+ * `src/components/component-meta.json`.
34
+ */
35
+ export function componentDescription(paragraphs: string[]): { component: string } {
36
+ return { component: [COMPONENT_POINTER, ...paragraphs].join('\n\n') };
37
+ }
38
+
39
+ /**
40
+ * Parse a type string from element-meta.json into meaningful parts.
41
+ *
42
+ * The meta generator writes types like:
43
+ * - `"undefined | false | true"` for booleans (NOT "boolean")
44
+ * - `"undefined | \"preview\" | \"code\""` for enums (double-quoted, with leading undefined)
45
+ *
46
+ * We normalise by splitting on `|`, trimming, and dropping `undefined` / `null`.
47
+ */
48
+ const normaliseParts = (type: string): string[] =>
49
+ type
50
+ .split('|')
51
+ .map((s) => s.trim())
52
+ .filter((s) => s !== 'undefined' && s !== 'null');
53
+
54
+ const enumValues = (parts: string[]): string[] | null => {
55
+ // Accept both single-quoted ('foo') and double-quoted ("foo") string literals.
56
+ if (parts.length > 0 && parts.every((p) => /^(['"])[^'"]*\1$/.test(p)))
57
+ return parts.map((p) => p.slice(1, -1));
58
+ return null;
59
+ };
60
+
61
+ const isBooleanParts = (parts: string[], rawType: string): boolean => {
62
+ // Explicit boolean keyword (future-proof)
63
+ if (/\bboolean\b/.test(rawType)) return true;
64
+ // element-meta encodes booleans as "undefined | false | true"
65
+ const sorted = [...parts].sort().join(',');
66
+ return sorted === 'false,true';
67
+ };
68
+
69
+ /**
70
+ * Storybook argTypes for an element's props (theme select, booleans, text,
71
+ * number, object/JSON for complex types, and no control for functions).
72
+ *
73
+ * Classification order:
74
+ * 1. enum → select
75
+ * 2. boolean → boolean
76
+ * 3. number → number
77
+ * 4. contains `=>` (function / function-bearing object) → control: false
78
+ * 5. not all-string after normalisation (arrays, records, generics…) → object
79
+ * 6. all-string → text
80
+ */
81
+ export function argTypesFor(tag: string): Record<string, unknown> {
82
+ const el = all.find((e) => e.tag === tag);
83
+ if (!el) return {};
84
+ const out: Record<string, unknown> = {};
85
+ for (const p of el.props) {
86
+ const parts = normaliseParts(p.type);
87
+
88
+ // 1–3: scalar classifications (enums, booleans, numbers only appear in scalar props)
89
+ if (p.scalar) {
90
+ const values = enumValues(parts);
91
+ if (values) {
92
+ out[p.name] = { control: { type: 'select' }, options: values };
93
+ continue;
94
+ }
95
+ if (isBooleanParts(parts, p.type)) {
96
+ out[p.name] = { control: 'boolean' };
97
+ continue;
98
+ }
99
+ if (/\bnumber\b/.test(p.type)) {
100
+ out[p.name] = { control: 'number' };
101
+ continue;
102
+ }
103
+ }
104
+
105
+ // 4. Function / function-bearing object: contains `=>` in raw type string
106
+ if (p.type.includes('=>')) {
107
+ out[p.name] = { control: false };
108
+ continue;
109
+ }
110
+
111
+ // 5. Complex/object: parts are not all exactly the string "string"
112
+ if (!parts.every((part) => part === 'string')) {
113
+ out[p.name] = { control: 'object' };
114
+ continue;
115
+ }
116
+
117
+ // 6. Pure string
118
+ out[p.name] = { control: 'text' };
119
+ }
120
+ return out;
121
+ }
@@ -0,0 +1,245 @@
1
+ import { Meta } from '@storybook/addon-docs/blocks';
2
+
3
+ <Meta title="Docs/Frameworks/Angular" />
4
+
5
+ # Angular
6
+
7
+ Angular needs **no wrappers** — its property binding (`[prop]="value"`) assigns the DOM **property**
8
+ directly, so arrays and objects pass through unstringified. Register the elements once, allow the
9
+ custom tags with `CUSTOM_ELEMENTS_SCHEMA`, and handle events with `(event)="handler($event)"`.
10
+
11
+ There are **two ways to build with the kit**, and you can mix them:
12
+
13
+ 1. **`<kai-chat>`** — the batteries-included shell: a whole chat experience in one tag. Fastest start.
14
+ 2. **Compose the individual elements** (`<kai-conversations>`, `<kai-markdown>`, `<kai-artifact>`, …)
15
+ into your own layout when you want full control.
16
+
17
+ Both are shown below.
18
+
19
+ ## Install & setup
20
+
21
+ ```bash
22
+ npm i @kitn.ai/ui
23
+ ```
24
+
25
+ Register the custom elements once as a static side-effect import in `main.ts`, **before**
26
+ `bootstrapApplication(...)`. Then add `CUSTOM_ELEMENTS_SCHEMA` to each standalone component that
27
+ uses `<kai-*>` tags:
28
+
29
+ ```ts
30
+ // main.ts — import BEFORE bootstrapApplication so elements are defined first
31
+ import '@kitn.ai/ui/elements';
32
+ import { bootstrapApplication } from '@angular/platform-browser';
33
+ import { AppComponent } from './app/app.component';
34
+ import { appConfig } from './app/app.config';
35
+
36
+ bootstrapApplication(AppComponent, appConfig);
37
+ ```
38
+
39
+ ```ts
40
+ // app.component.ts
41
+ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
42
+
43
+ @Component({
44
+ selector: 'app-root',
45
+ standalone: true,
46
+ templateUrl: './app.component.html',
47
+ schemas: [CUSTOM_ELEMENTS_SCHEMA], // required: allows <kai-*> tags in the template
48
+ })
49
+ export class AppComponent { /* … */ }
50
+ ```
51
+
52
+ - **`@kitn.ai/ui/elements`** — the side-effect import that registers every `<kai-*>` element
53
+ globally. Import it once, in `main.ts`.
54
+ - **`CUSTOM_ELEMENTS_SCHEMA`** — tells the Angular compiler to accept unknown element names (the
55
+ `<kai-*>` tags). Add it to every standalone component whose template uses them.
56
+ - No CSS to import: each element is styled inside its own Shadow DOM. Only pull in
57
+ `@kitn.ai/ui/theme.css` if you want to override design tokens (see **Theming**).
58
+
59
+ ## Quick start — the all-in-one shell
60
+
61
+ `<kai-chat>` is **transport-agnostic**: give it a `messages` array, handle the `submit` event, and
62
+ stream your model's reply back into state. You own the request; the component owns the UI.
63
+
64
+ ```ts
65
+ // app.component.ts
66
+ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
67
+
68
+ type Message = { id: string; role: 'user' | 'assistant'; content: string };
69
+
70
+ @Component({
71
+ selector: 'app-root',
72
+ standalone: true,
73
+ templateUrl: './app.component.html',
74
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
75
+ })
76
+ export class AppComponent {
77
+ messages: Message[] = [
78
+ { id: '1', role: 'assistant', content: 'Hello! How can I help?' },
79
+ ];
80
+
81
+ async onSubmit(e: Event) {
82
+ const { value } = (e as CustomEvent<{ value: string }>).detail;
83
+ // Reassign a NEW array so Angular's change detection picks it up.
84
+ const history = [...this.messages, { id: crypto.randomUUID(), role: 'user' as const, content: value }];
85
+ this.messages = history;
86
+
87
+ const aid = crypto.randomUUID();
88
+ this.messages = [...history, { id: aid, role: 'assistant' as const, content: '' }];
89
+
90
+ let answer = '';
91
+ for await (const token of streamFromYourAPI(history)) {
92
+ answer += token;
93
+ // Reassign a new array — and a new object for the message being streamed.
94
+ this.messages = this.messages.map((m) =>
95
+ m.id === aid ? { ...m, content: answer } : m
96
+ );
97
+ }
98
+ }
99
+ }
100
+ ```
101
+
102
+ ```html
103
+ <!-- app.component.html -->
104
+ <!-- The elements are display:block and fill their container — lay them out with flex
105
+ and let the element grow with flex:1 rather than hard-coding a height. -->
106
+ <div style="display: flex; flex-direction: column; height: 100dvh">
107
+ <kai-chat
108
+ [messages]="messages"
109
+ (kai-submit)="onSubmit($event)"
110
+ style="flex: 1; min-height: 0"
111
+ ></kai-chat>
112
+ </div>
113
+ ```
114
+
115
+ ## Go further — compose the pieces
116
+
117
+ `<kai-chat>` is one option, not the only one. You can assemble your own layout from individual
118
+ elements. Here is a multi-conversation shell — a `<kai-conversations>` sidebar next to the
119
+ `<kai-chat>` thread:
120
+
121
+ ```ts
122
+ // workspace.component.ts
123
+ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
124
+
125
+ @Component({
126
+ selector: 'app-workspace',
127
+ standalone: true,
128
+ templateUrl: './workspace.component.html',
129
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
130
+ })
131
+ export class WorkspaceComponent {
132
+ conversations = myConversations;
133
+ activeId = this.conversations[0]?.id;
134
+ messages = loadMessages(this.activeId);
135
+
136
+ onConversationSelect(e: Event) {
137
+ this.activeId = (e as CustomEvent<{ id: string }>).detail.id;
138
+ this.messages = loadMessages(this.activeId);
139
+ }
140
+
141
+ onNewChat() {
142
+ startNewConversation();
143
+ }
144
+
145
+ onSubmit(e: Event) {
146
+ const { value } = (e as CustomEvent<{ value: string }>).detail;
147
+ sendMessage(value);
148
+ }
149
+ }
150
+ ```
151
+
152
+ ```html
153
+ <!-- workspace.component.html -->
154
+ <!-- Lay panels out with flex: the sidebar is fixed-width, the thread takes the rest
155
+ with flex:1. The elements fill whatever box you give them. -->
156
+ <div style="display: flex; height: 100dvh">
157
+ <kai-conversations
158
+ [conversations]="conversations"
159
+ [activeId]="activeId"
160
+ (kai-conversation-select)="onConversationSelect($event)"
161
+ (kai-new-chat)="onNewChat()"
162
+ style="width: 300px; flex-shrink: 0"
163
+ ></kai-conversations>
164
+
165
+ <kai-chat
166
+ [messages]="messages"
167
+ (kai-submit)="onSubmit($event)"
168
+ style="flex: 1; min-width: 0"
169
+ ></kai-chat>
170
+ </div>
171
+ ```
172
+
173
+ ### Make the panels resizable
174
+
175
+ Want a draggable divider between the sidebar and the thread? Wrap the panels in `<kai-resizable>`
176
+ with one `<kai-resizable-item>` each — the handles are inserted for you (up to 3 panels). Each item
177
+ takes a `size` (px or `%`) plus optional `min`/`max`; listen for `(change)` (`$event.detail.sizes`)
178
+ to persist the layout.
179
+
180
+ ```html
181
+ <div style="display: flex; flex-direction: column; height: 100dvh">
182
+ <kai-resizable
183
+ orientation="horizontal"
184
+ (kai-change)="onResize($event)"
185
+ style="flex: 1; min-height: 0"
186
+ >
187
+ <kai-resizable-item size="25%" min="200px">
188
+ <kai-conversations
189
+ [conversations]="conversations"
190
+ [activeId]="activeId"
191
+ (kai-conversation-select)="onConversationSelect($event)"
192
+ ></kai-conversations>
193
+ </kai-resizable-item>
194
+ <kai-resizable-item>
195
+ <kai-chat [messages]="messages" (kai-submit)="onSubmit($event)"></kai-chat>
196
+ </kai-resizable-item>
197
+ </kai-resizable>
198
+ </div>
199
+ ```
200
+
201
+ ```ts
202
+ onResize(e: Event) {
203
+ const { sizes } = (e as CustomEvent<{ sizes: string[] }>).detail;
204
+ // persist sizes to localStorage, a service, etc.
205
+ console.log('panel sizes:', sizes);
206
+ }
207
+ ```
208
+
209
+ You can also drop **standalone display elements** anywhere in your own UI — `<kai-markdown>`,
210
+ `<kai-code-block>`, `<kai-artifact>`, `<kai-reasoning>`, `<kai-tool>` — to render rich AI content
211
+ without adopting the whole chat. Each fills its container and is controlled via `[prop]` bindings
212
+ and `(event)` listeners.
213
+
214
+ > **See it all assembled:** **[Examples → Full Chat App](?path=/story/examples-full-chat-app--default)**
215
+ > wires a sidebar, threaded markdown, reasoning, a tool call, a model switcher, a context meter, and
216
+ > a rich prompt input into one screen — a working reference to crib from.
217
+
218
+ > **Find every element:** browse the **Components** section in the sidebar. Each element's **API**
219
+ > tab lists its props, events, and copy-paste usage for Angular (and every other framework).
220
+
221
+ ## Props & events
222
+
223
+ The rule for all elements: **rich data goes in as properties, interactions come out as events.**
224
+ Angular's `[prop]="…"` binding writes to the element's DOM property (not an HTML attribute), so
225
+ arrays and objects pass through unstringified — no adapter or wrapper needed.
226
+
227
+ `(event)="handler($event)"` listens for a DOM CustomEvent. `$event` is the `CustomEvent` itself;
228
+ read the payload from `$event.detail`:
229
+
230
+ | Element | Property binding | Event | `$event.detail` |
231
+ |---|---|---|---|
232
+ | `kai-chat` | `[messages]="messages"` | `(submit)` | `{ value: string }` |
233
+ | `kai-conversations` | `[conversations]="…"` | `(conversationselect)` | `{ id: string }` |
234
+ | `kai-conversations` | `[groups]="…"` | `(newchat)` | — |
235
+ | `kai-conversations` | — | `(togglesidebar)` | — |
236
+ | `kai-resizable` | `orientation="horizontal"` | `(change)` | `{ sizes: string[] }` |
237
+ | `kai-resizable-item` | `size="25%"` `min="200px"` `max="…"` | — | — |
238
+
239
+ > **Scalar attributes** like `orientation="horizontal"` or `theme="dark"` can be plain HTML
240
+ > attributes (no brackets). Use `[prop]="…"` only when passing non-string values (arrays, objects,
241
+ > booleans) or Angular expressions.
242
+
243
+ > **`CUSTOM_ELEMENTS_SCHEMA` is required** in every standalone component (or NgModule) whose
244
+ > template contains `<kai-*>` tags. Without it, the Angular compiler rejects unknown element names at
245
+ > build time.
@@ -0,0 +1,227 @@
1
+ import { Meta } from '@storybook/addon-docs/blocks';
2
+
3
+ <Meta title="Docs/Frameworks/HTML" />
4
+
5
+ # HTML
6
+
7
+ The kit ships as standard **custom elements** (`kai-*` tags) — no framework required. Import the
8
+ bundle once as a side-effect and every element is registered globally, ready to drop into any HTML
9
+ page or templating system.
10
+
11
+ There are **two ways to build with the kit**, and you can mix them:
12
+
13
+ 1. **`<kai-chat>`** — the batteries-included shell: a whole chat experience in one tag. Fastest start.
14
+ 2. **Compose the individual elements** (`<kai-conversations>`, `<kai-markdown>`, `<kai-artifact>`, …)
15
+ into your own layout when you want full control.
16
+
17
+ Both are shown below.
18
+
19
+ ## Install & setup
20
+
21
+ ```bash
22
+ npm i @kitn.ai/ui
23
+ ```
24
+
25
+ Register the custom elements once (a side-effect import), then use the tags anywhere in your HTML:
26
+
27
+ ```js
28
+ // Once, near your app entry — registers all <kai-*> elements globally.
29
+ import '@kitn.ai/ui/elements';
30
+ ```
31
+
32
+ - No CSS to import: each element is styled inside its own Shadow DOM. Only pull in
33
+ `@kitn.ai/ui/theme.css` if you want to override design tokens (see **Theming**).
34
+
35
+ ### No-build / CDN option
36
+
37
+ No bundler? Load the module directly from a CDN and you're done:
38
+
39
+ ```html
40
+ <script type="module">
41
+ import 'https://cdn.jsdelivr.net/npm/@kitn.ai/ui/dist/kitn-chat.es.js';
42
+ </script>
43
+ ```
44
+
45
+ Every `<kai-*>` element is then available as a global custom element — no install, no build step.
46
+
47
+ ## Quick start — the all-in-one shell
48
+
49
+ `<kai-chat>` is **transport-agnostic**: give it a `messages` array, handle the `submit` event, and
50
+ stream your model's reply back into the property. You own the request; the element owns the UI.
51
+
52
+ ```html
53
+ <!DOCTYPE html>
54
+ <html>
55
+ <head>
56
+ <!-- optional: only needed to override design tokens -->
57
+ <link rel="stylesheet" href="./node_modules/@kitn.ai/ui/theme.css" />
58
+ <style>
59
+ html, body { margin: 0; height: 100%; }
60
+ .app { display: flex; flex-direction: column; height: 100dvh; }
61
+ </style>
62
+ </head>
63
+ <body>
64
+ <!-- Put the element in a flex parent and give it flex: 1.
65
+ The elements are display:block and fill their box. -->
66
+ <div class="app">
67
+ <kai-chat id="chat" style="flex: 1; min-height: 0;"></kai-chat>
68
+ </div>
69
+
70
+ <script type="module">
71
+ import '@kitn.ai/ui/elements';
72
+
73
+ const chat = document.getElementById('chat');
74
+
75
+ // Arrays and objects → JS properties (never attributes)
76
+ chat.messages = [
77
+ { id: '1', role: 'assistant', content: 'Hello! How can I help?', actions: ['copy', 'like', 'dislike'] },
78
+ ];
79
+ chat.suggestions = ['Summarize the chat', 'Start fresh'];
80
+
81
+ // Interactions → addEventListener (CustomEvents, they don't bubble)
82
+ chat.addEventListener('kai-submit', async (e) => {
83
+ const text = e.detail.value;
84
+
85
+ // Append user message — always assign a NEW array to trigger a re-render
86
+ const history = [...chat.messages, { id: crypto.randomUUID(), role: 'user', content: text }];
87
+ chat.messages = history;
88
+ chat.loading = true;
89
+
90
+ // Stream into an empty assistant placeholder
91
+ const aid = crypto.randomUUID();
92
+ chat.messages = [...history, { id: aid, role: 'assistant', content: '' }];
93
+
94
+ let answer = '';
95
+ for await (const token of streamFromYourAPI(history)) {
96
+ answer += token;
97
+ // Replace the placeholder with a new object each chunk
98
+ chat.messages = chat.messages.map((m) =>
99
+ m.id === aid ? { ...m, content: answer } : m
100
+ );
101
+ }
102
+ chat.loading = false;
103
+ });
104
+ </script>
105
+ </body>
106
+ </html>
107
+ ```
108
+
109
+ > **Reactivity:** always assign a **new array** (and a new object for any message you change).
110
+ > Mutating an existing object in place will not trigger a re-render.
111
+
112
+ ## Go further — compose the pieces
113
+
114
+ `<kai-chat>` is one option, not the only one. Every element can be placed independently, so you can
115
+ assemble your own layout. Here's a multi-conversation shell — a `<kai-conversations>` sidebar next
116
+ to the `<kai-chat>` thread:
117
+
118
+ ```html
119
+ <style>
120
+ html, body { margin: 0; height: 100%; }
121
+ .workspace { display: flex; height: 100dvh; }
122
+ </style>
123
+
124
+ <div class="workspace">
125
+ <kai-conversations id="sidebar" style="width: 300px; flex-shrink: 0;"></kai-conversations>
126
+ <kai-chat id="chat" style="flex: 1; min-width: 0;"></kai-chat>
127
+ </div>
128
+
129
+ <script type="module">
130
+ import '@kitn.ai/ui/elements';
131
+
132
+ const sidebar = document.getElementById('sidebar');
133
+ const chat = document.getElementById('chat');
134
+
135
+ // Rich data → JS properties
136
+ sidebar.conversations = myConversations;
137
+ chat.messages = loadMessages(myConversations[0]?.id);
138
+
139
+ sidebar.addEventListener('kai-conversation-select', (e) => {
140
+ chat.messages = loadMessages(e.detail.id);
141
+ });
142
+
143
+ sidebar.addEventListener('kai-new-chat', () => startNewConversation());
144
+
145
+ chat.addEventListener('kai-submit', (e) => sendMessage(e.detail.value));
146
+ </script>
147
+ ```
148
+
149
+ ### Make the panels resizable
150
+
151
+ Want a draggable divider between the sidebar and the thread? Wrap the panels in `<kai-resizable>`
152
+ with one `<kai-resizable-item>` each — the handles are inserted for you (up to 3 panels). Each item
153
+ takes a `size` (px or `%`) plus optional `min`/`max`; listen for `change` (`detail.sizes`) to
154
+ persist the layout.
155
+
156
+ ```html
157
+ <style>
158
+ html, body { margin: 0; height: 100%; }
159
+ .app { display: flex; flex-direction: column; height: 100dvh; }
160
+ </style>
161
+
162
+ <div class="app">
163
+ <kai-resizable orientation="horizontal" style="flex: 1; min-height: 0;">
164
+ <kai-resizable-item size="25%" min="200px">
165
+ <kai-conversations id="sidebar"></kai-conversations>
166
+ </kai-resizable-item>
167
+ <kai-resizable-item>
168
+ <kai-chat id="chat"></kai-chat>
169
+ </kai-resizable-item>
170
+ </kai-resizable>
171
+ </div>
172
+
173
+ <script type="module">
174
+ import '@kitn.ai/ui/elements';
175
+
176
+ const resizable = document.querySelector('kai-resizable');
177
+ resizable.addEventListener('kai-change', (e) => {
178
+ console.log('panel sizes:', e.detail.sizes);
179
+ // persist to localStorage, etc.
180
+ });
181
+ </script>
182
+ ```
183
+
184
+ You can also drop **standalone display elements** anywhere in your own page — `<kai-markdown>`,
185
+ `<kai-code-block>`, `<kai-artifact>` — to render rich AI content without adopting the whole chat.
186
+ Each element fills its container and is controlled via properties and events.
187
+
188
+ > **See it all assembled:** **[Examples → Full Chat App](?path=/story/examples-full-chat-app--default)**
189
+ > wires a sidebar, threaded markdown, a model switcher, a context meter, and a rich prompt input
190
+ > into one screen — a working reference to crib from.
191
+
192
+ > **Find every element:** browse the **Components** section in the sidebar. Each element's **API**
193
+ > tab lists its props, events, and copy-paste usage for HTML (and every other framework).
194
+
195
+ ## Props & events
196
+
197
+ The rule for all elements: **rich data goes in as JS properties, interactions come out as events.**
198
+
199
+ ```js
200
+ // ✅ Arrays and objects — always set as a JS property
201
+ el.messages = [{ id: '1', role: 'assistant', content: 'Hi' }];
202
+ el.conversations = myConversations;
203
+
204
+ // ✅ Events — addEventListener on the element (CustomEvents, they don't bubble)
205
+ el.addEventListener('kai-submit', (e) => console.log(e.detail.value));
206
+ el.addEventListener('kai-conversation-select', (e) => console.log(e.detail.id));
207
+ ```
208
+
209
+ **Scalar attributes** (strings, booleans, numbers) can go directly in HTML markup:
210
+
211
+ ```html
212
+ <!-- theme, placeholder, and loading are scalars → safe as attributes -->
213
+ <kai-chat
214
+ theme="dark"
215
+ placeholder="Ask anything…"
216
+ ></kai-chat>
217
+ ```
218
+
219
+ Key events by element:
220
+
221
+ | Element | Event | `detail` |
222
+ |---|---|---|
223
+ | `kai-chat` | `submit` | `{ value: string }` |
224
+ | `kai-conversations` | `conversationselect` | `{ id: string }` |
225
+ | `kai-conversations` | `newchat` | — |
226
+ | `kai-conversations` | `togglesidebar` | — |
227
+ | `kai-resizable` | `change` | `{ sizes: string[] }` |