@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,88 @@
1
+ import type { Meta, StoryObj } from 'storybook-solidjs-vite';
2
+ import { onMount } from 'solid-js';
3
+ import './register'; // side effect: registers the custom elements
4
+ import { argTypesFor, specDescription } from '../stories/docs/element-controls';
5
+
6
+ // The web components are custom DOM elements, so declare the tags for JSX.
7
+ declare module 'solid-js' {
8
+ // eslint-disable-next-line @typescript-eslint/no-namespace
9
+ namespace JSX {
10
+ interface IntrinsicElements {
11
+ 'kai-source': JSX.HTMLAttributes<HTMLElement> & { href?: string; label?: string; headline?: string; description?: string; 'show-favicon'?: boolean | '' };
12
+ }
13
+ }
14
+ }
15
+
16
+ /** Render the actual `<kai-source>` custom element configured by attributes. */
17
+ function SourceElement(props: {
18
+ href: string;
19
+ label?: string;
20
+ headline?: string;
21
+ description?: string;
22
+ showFavicon?: boolean;
23
+ }) {
24
+ let el: HTMLElement | undefined;
25
+ onMount(() => {
26
+ if (!el) return;
27
+ el.setAttribute('href', props.href);
28
+ if (props.label) el.setAttribute('label', props.label);
29
+ if (props.headline) el.setAttribute('headline', props.headline);
30
+ if (props.description) el.setAttribute('description', props.description);
31
+ if (props.showFavicon) el.setAttribute('show-favicon', '');
32
+ });
33
+ return <kai-source ref={(e) => (el = e as HTMLElement)} style={{ display: 'inline-block', padding: '16px' }} />;
34
+ }
35
+
36
+ const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
37
+ <kai-source
38
+ href="https://kitn.dev"
39
+ label="kitn"
40
+ headline="kitn — the kit"
41
+ description="Composable SolidJS + web-component chat UI."
42
+ show-favicon
43
+ ></kai-source>
44
+
45
+ <script type="module">
46
+ import '@kitn.ai/ui/elements'; // registers the custom elements
47
+ </script>`;
48
+
49
+ const meta = {
50
+ title: 'Components/Source',
51
+ tags: ['autodocs'],
52
+ argTypes: argTypesFor('kai-source'),
53
+ parameters: {
54
+ layout: 'fullscreen',
55
+ docs: {
56
+ description: specDescription('kai-source', [
57
+ '`<kai-source>` is the framework-agnostic **web component** for a single citation link with a hover-card preview, isolated in **Shadow DOM**.',
58
+ '**When to use:** inlining a single source citation in a non-Solid app. For multiple sources, use `<kai-sources>`; in SolidJS, compose the `Source` primitives.',
59
+ '**Placement:** inline within message text (beside a sentence or at the end of a paragraph) or as a standalone citation chip below a message; it is an `inline-block` element that fits naturally within flow content.',
60
+ "**How to use:** register once with `import '@kitn.ai/ui/elements'`, then set `href` (the link, also the default label/favicon source), `label`, `headline` (the hover headline — note `headline`, not `title`), `description`, and the `show-favicon` flag via attributes.",
61
+ 'See the **Code** tab for HTML usage.',
62
+ ]),
63
+ },
64
+ },
65
+ } satisfies Meta;
66
+
67
+ export default meta;
68
+ type Story = StoryObj;
69
+
70
+ /** A citation with a custom label, hover headline/description, and favicon. */
71
+ export const Default: Story = {
72
+ render: () => (
73
+ <SourceElement
74
+ href="https://kitn.dev"
75
+ label="kitn"
76
+ headline="kitn — the kit"
77
+ description="Composable SolidJS + web-component chat UI."
78
+ showFavicon
79
+ />
80
+ ),
81
+ parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
82
+ };
83
+
84
+ /** With no `label`, the trigger falls back to the domain. */
85
+ export const DomainLabel: Story = {
86
+ name: 'Domain Label',
87
+ render: () => <SourceElement href="https://solidjs.com" description="A reactive UI library." />,
88
+ };
@@ -0,0 +1,120 @@
1
+ import { createSignal, For, onCleanup, onMount, Show } from 'solid-js';
2
+ import { defineWebComponent } from './define';
3
+ import { Source, SourceTrigger, SourceContent, SourceList } from '../components/source';
4
+
5
+ // --- <kai-source> — a single citation link with hover preview ---
6
+
7
+ interface SourceProps extends Record<string, unknown> {
8
+ /** The URL this citation links to (the domain also seeds the default label/favicon). */
9
+ href?: string;
10
+ /** Trigger label (defaults to the domain). */
11
+ label?: string;
12
+ /** Hover-card headline. Attribute: `headline` (`title` is avoided — it's a
13
+ * global HTML attribute that reflects in a CE constructor and breaks it). */
14
+ headline?: string;
15
+ /** Hover-card body text describing the source. */
16
+ description?: string;
17
+ /** Show the source's favicon next to the trigger label. */
18
+ showFavicon?: boolean;
19
+ }
20
+
21
+ defineWebComponent<SourceProps>('kai-source', {
22
+ href: '',
23
+ label: undefined,
24
+ headline: '',
25
+ description: '',
26
+ showFavicon: false,
27
+ }, (props, { flag }) => (
28
+ <Show when={props.href}>
29
+ <Source href={props.href!}>
30
+ <SourceTrigger label={props.label} showFavicon={flag('showFavicon')} />
31
+ <SourceContent title={props.headline ?? ''} description={props.description ?? ''} />
32
+ </Source>
33
+ </Show>
34
+ ));
35
+
36
+ // --- <kai-sources> — a wrapped list of citation links ---
37
+
38
+ interface SourceItem {
39
+ href: string;
40
+ title?: string;
41
+ description?: string;
42
+ label?: string;
43
+ showFavicon?: boolean;
44
+ }
45
+
46
+ interface SourceListProps extends Record<string, unknown> {
47
+ /** The sources to render. Set as a JS property. */
48
+ sources: SourceItem[];
49
+ /** Show favicons on all items (per-item `showFavicon` overrides). */
50
+ showFavicon?: boolean;
51
+ /**
52
+ * When true, each citation chip is labelled with its 1-based index in the
53
+ * merged (prop + declarative-children) list (`[1]`, `[2]`, …) instead of the
54
+ * per-item `label` or domain fallback.
55
+ *
56
+ * HTML attribute: `numbered` (boolean — bare attribute or `numbered="true"`).
57
+ * JS property: `el.numbered = true`.
58
+ */
59
+ numbered?: boolean;
60
+ }
61
+
62
+ /** Parse a single light-DOM `<kai-source>` element into a `SourceItem` descriptor.
63
+ * Attribute mapping:
64
+ * - `href` → SourceItem.href
65
+ * - `label` → SourceItem.label
66
+ * - `headline` → SourceItem.title (matches kai-source's prop name; "title" is a
67
+ * reserved HTMLElement attribute so kai-source uses "headline")
68
+ * - `description` → SourceItem.description
69
+ * - `show-favicon`→ SourceItem.showFavicon (bare boolean attribute)
70
+ */
71
+ export function parseKaiSourceElement(n: Element): SourceItem {
72
+ return {
73
+ href: n.getAttribute('href') ?? '',
74
+ label: n.getAttribute('label') ?? undefined,
75
+ title: n.getAttribute('headline') ?? undefined,
76
+ description: n.getAttribute('description') ?? undefined,
77
+ showFavicon: n.hasAttribute('show-favicon') && n.getAttribute('show-favicon') !== 'false',
78
+ };
79
+ }
80
+
81
+ defineWebComponent<SourceListProps>('kai-sources', {
82
+ sources: [],
83
+ showFavicon: false,
84
+ numbered: false,
85
+ }, (props, { element, flag }) => {
86
+ // Read declarative <kai-source> children from light DOM.
87
+ // The shadow root has no <slot> for them, so they are invisible — pure data carriers.
88
+ const [slottedSources, setSlottedSources] = createSignal<SourceItem[]>([]);
89
+ onMount(() => {
90
+ const read = () => {
91
+ const nodes = [...element.querySelectorAll('kai-source')];
92
+ setSlottedSources(nodes.map(parseKaiSourceElement));
93
+ };
94
+ read();
95
+ const observer = new MutationObserver(read);
96
+ observer.observe(element, { childList: true, attributes: true, subtree: true });
97
+ onCleanup(() => observer.disconnect());
98
+ });
99
+
100
+ // Prop sources take precedence; slotted children are appended after.
101
+ const allSources = () => [...props.sources, ...slottedSources()];
102
+
103
+ const isNumbered = () => flag('numbered');
104
+
105
+ return (
106
+ <SourceList>
107
+ <For each={allSources()}>
108
+ {(s, i) => (
109
+ <Source href={s.href}>
110
+ <SourceTrigger
111
+ label={isNumbered() ? i() + 1 : s.label}
112
+ showFavicon={s.showFavicon ?? flag('showFavicon')}
113
+ />
114
+ <SourceContent title={s.title ?? ''} description={s.description ?? ''} />
115
+ </Source>
116
+ )}
117
+ </For>
118
+ </SourceList>
119
+ );
120
+ });
@@ -0,0 +1,199 @@
1
+ /* Element-bundle stylesheet. Compiled to compiled.css and injected into each
2
+ custom element's shadow root. Mirrors .storybook/styles.css but scans src/. */
3
+ @import "tailwindcss";
4
+ @import "../../theme.css";
5
+ @plugin "@tailwindcss/typography";
6
+
7
+ @source "../";
8
+
9
+ @layer base {
10
+ /* Base typography is token-driven so a theme can restyle it. --kai-font-base is
11
+ the family for ALL text/UI (named "base", not "sans", so a serif body works);
12
+ --kai-tracking is global letter-spacing. Both pierce the Shadow DOM via the
13
+ var() fallback, exactly like the --kai-color-* tokens. */
14
+ :host {
15
+ display: block;
16
+ font-family: var(--kai-font-base, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);
17
+ letter-spacing: var(--kai-tracking, normal);
18
+ }
19
+ /* Code/monospace surfaces use --kai-font-code (named for its ROLE — code — not
20
+ "mono", so any family works). Covers inline code, <pre>, and code blocks. */
21
+ code, kbd, samp, pre {
22
+ font-family: var(--kai-font-code, ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace);
23
+ }
24
+ * { border-color: var(--color-border); }
25
+
26
+ /* Native controls (date/time pickers, <select>, number spinners, the
27
+ checkbox/radio fallbacks, scrollbars) must follow the kit's light/dark
28
+ mode — NOT the OS — so e.g. the native calendar icon never renders black
29
+ on a dark surface. `color-scheme` drives that native rendering; we set it
30
+ from the resolved mode (the `.dark` scope the element factory toggles). */
31
+ :host { color-scheme: light; }
32
+ .dark { color-scheme: dark; }
33
+
34
+ /* One token-driven focus ring for EVERY focusable element in the shadow root.
35
+ Blue by default (via --color-ring), consistent in light + dark, and
36
+ overridable through --kai-color-ring. Uses `outline` (not a box-shadow
37
+ ring) so it never clips on overflow and follows the element's radius;
38
+ `:focus-visible` so it only appears for keyboard navigation, never on a
39
+ mouse click. Components that render their own ring set
40
+ `focus-visible:outline-none` (a utility in a later cascade layer) and win
41
+ over this — so there's no double ring, just a guaranteed blue fallback for
42
+ the many controls that have no explicit focus style. */
43
+ :focus-visible {
44
+ outline: 2px solid var(--color-ring);
45
+ outline-offset: 2px;
46
+ }
47
+
48
+ /* Consistent cross-platform scrollbars for EVERY scroll region inside the
49
+ shadow root (message list, conversation list, menus, hover cards, code
50
+ blocks, the prompt textarea …). Thin + rounded + subtle, themed via tokens
51
+ for light/dark, thumb stronger on hover. Track stays transparent and
52
+ overflow is untouched, so no scrollbar is forced where none is needed.
53
+ Scoped to the shadow root, so it never restyles the host page. */
54
+ * {
55
+ scrollbar-width: thin;
56
+ scrollbar-color: var(--color-scrollbar-thumb) transparent;
57
+ }
58
+ *::-webkit-scrollbar { width: 8px; height: 8px; }
59
+ *::-webkit-scrollbar-track { background: transparent; }
60
+ *::-webkit-scrollbar-thumb {
61
+ background-color: var(--color-scrollbar-thumb);
62
+ border-radius: 9999px;
63
+ border: 2px solid transparent;
64
+ background-clip: padding-box;
65
+ }
66
+ *::-webkit-scrollbar-thumb:hover { background-color: var(--color-scrollbar-thumb-hover); }
67
+ *::-webkit-scrollbar-corner { background: transparent; }
68
+ }
69
+
70
+ @layer components {
71
+ /* Designed radio + checkbox (appearance-none) so the form controls read as
72
+ intentional, theme correctly in light/dark, and have comfortable targets —
73
+ replacing the weak native defaults. Used via `.kai-radio` / `.kai-checkbox`. */
74
+ .kai-radio,
75
+ .kai-checkbox {
76
+ appearance: none;
77
+ -webkit-appearance: none;
78
+ inline-size: 1.125rem;
79
+ block-size: 1.125rem;
80
+ margin: 0;
81
+ flex-shrink: 0;
82
+ cursor: pointer;
83
+ border: 1.5px solid var(--color-input);
84
+ background-color: var(--color-background);
85
+ display: inline-grid;
86
+ place-content: center;
87
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.04);
88
+ transition: border-color 0.18s ease, background-color 0.18s ease, box-shadow 0.18s ease,
89
+ transform 0.1s ease;
90
+ }
91
+ .kai-radio { border-radius: 9999px; }
92
+ .kai-checkbox { border-radius: 0.3rem; }
93
+ .kai-radio::after {
94
+ content: "";
95
+ inline-size: 0.5rem;
96
+ block-size: 0.5rem;
97
+ border-radius: 9999px;
98
+ background-color: var(--color-primary);
99
+ transform: scale(0);
100
+ transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
101
+ }
102
+ .kai-radio:checked { border-color: var(--color-primary); }
103
+ .kai-radio:checked::after { transform: scale(1); }
104
+ .kai-checkbox:checked {
105
+ background-color: var(--color-primary);
106
+ border-color: var(--color-primary);
107
+ }
108
+ .kai-checkbox::after {
109
+ content: "";
110
+ inline-size: 0.8rem;
111
+ block-size: 0.8rem;
112
+ background-color: var(--color-primary-foreground);
113
+ transform: scale(0);
114
+ transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
115
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
116
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
117
+ }
118
+ .kai-checkbox:checked::after { transform: scale(1); }
119
+ .kai-radio:hover:not(:disabled),
120
+ .kai-checkbox:hover:not(:disabled) {
121
+ border-color: var(--color-primary);
122
+ box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-primary) 9%, transparent);
123
+ }
124
+ .kai-radio:active:not(:disabled),
125
+ .kai-checkbox:active:not(:disabled) { transform: scale(0.92); }
126
+ .kai-checkbox:checked {
127
+ box-shadow: 0 1px 4px color-mix(in srgb, var(--color-primary) 26%, transparent);
128
+ }
129
+ .kai-radio:disabled,
130
+ .kai-checkbox:disabled { opacity: 0.5; cursor: not-allowed; }
131
+
132
+ /* Custom range slider: a filled track (--kai-range-fill set by the widget) and a
133
+ refined thumb that scales on hover/press with a focus halo — no native chrome. */
134
+ .kai-range {
135
+ appearance: none;
136
+ -webkit-appearance: none;
137
+ inline-size: 100%;
138
+ block-size: 1.25rem;
139
+ background: transparent;
140
+ cursor: pointer;
141
+ margin: 0;
142
+ }
143
+ .kai-range::-webkit-slider-runnable-track {
144
+ block-size: 0.375rem;
145
+ border-radius: 9999px;
146
+ border: none;
147
+ box-shadow: none;
148
+ background: linear-gradient(
149
+ to right,
150
+ var(--color-primary) var(--kai-range-fill, 0%),
151
+ var(--color-muted) var(--kai-range-fill, 0%)
152
+ );
153
+ }
154
+ .kai-range::-moz-range-track {
155
+ block-size: 0.375rem;
156
+ border-radius: 9999px;
157
+ border: none;
158
+ box-shadow: none;
159
+ background: var(--color-muted);
160
+ }
161
+ .kai-range::-moz-range-progress {
162
+ block-size: 0.375rem;
163
+ border-radius: 9999px;
164
+ background: var(--color-primary);
165
+ }
166
+ .kai-range::-webkit-slider-thumb {
167
+ appearance: none;
168
+ -webkit-appearance: none;
169
+ inline-size: 1.125rem;
170
+ block-size: 1.125rem;
171
+ border-radius: 9999px;
172
+ background: var(--color-background);
173
+ border: 2px solid var(--color-primary);
174
+ box-shadow: 0 1px 3px rgb(0 0 0 / 0.18);
175
+ margin-block-start: -0.375rem;
176
+ transition: transform 0.12s ease, box-shadow 0.12s ease;
177
+ }
178
+ .kai-range::-moz-range-thumb {
179
+ inline-size: 1.125rem;
180
+ block-size: 1.125rem;
181
+ border-radius: 9999px;
182
+ background: var(--color-background);
183
+ border: 2px solid var(--color-primary);
184
+ box-shadow: 0 1px 3px rgb(0 0 0 / 0.18);
185
+ transition: transform 0.12s ease, box-shadow 0.12s ease;
186
+ }
187
+ .kai-range:hover::-webkit-slider-thumb { transform: scale(1.12); }
188
+ .kai-range:hover::-moz-range-thumb { transform: scale(1.12); }
189
+ .kai-range:focus-visible { outline: none; }
190
+ .kai-range:focus-visible::-webkit-slider-thumb,
191
+ .kai-range:active::-webkit-slider-thumb {
192
+ box-shadow: 0 0 0 6px color-mix(in srgb, var(--color-primary) 14%, transparent);
193
+ }
194
+ .kai-range:focus-visible::-moz-range-thumb,
195
+ .kai-range:active::-moz-range-thumb {
196
+ box-shadow: 0 0 0 6px color-mix(in srgb, var(--color-primary) 14%, transparent);
197
+ }
198
+ .kai-range:disabled { opacity: 0.5; cursor: not-allowed; }
199
+ }
@@ -0,0 +1,56 @@
1
+ import type { Meta, StoryObj } from 'storybook-solidjs-vite';
2
+ import { onMount } from 'solid-js';
3
+ import './register'; // side effect: registers the custom elements
4
+ import { argTypesFor, specDescription } from '../stories/docs/element-controls';
5
+
6
+ declare module 'solid-js' {
7
+ // eslint-disable-next-line @typescript-eslint/no-namespace
8
+ namespace JSX {
9
+ interface IntrinsicElements {
10
+ 'kai-switch': JSX.HTMLAttributes<HTMLElement> & { checked?: boolean | string; disabled?: boolean | string; label?: string };
11
+ }
12
+ }
13
+ }
14
+
15
+ const HTML_SNIPPET = `<kai-switch checked label="Temporary chat"></kai-switch>
16
+
17
+ <script type="module">
18
+ import '@kitn.ai/ui/elements'; // registers the custom elements
19
+ document.querySelector('kai-switch')
20
+ .addEventListener('kai-change', (e) => console.log('checked:', e.detail.checked));
21
+ </script>`;
22
+
23
+ const meta = {
24
+ title: 'Components/Switch',
25
+ tags: ['autodocs'],
26
+ argTypes: argTypesFor('kai-switch'),
27
+ parameters: {
28
+ layout: 'centered',
29
+ docs: {
30
+ description: specDescription('kai-switch', [
31
+ '`<kai-switch>` is the framework-agnostic **web component** toggle — a `role="switch"` control isolated in **Shadow DOM**. In SolidJS, use the `Switch` primitive.',
32
+ '**When to use:** an immediate on/off setting (e.g. "Temporary chat") in a header menu, settings row, or preference panel.',
33
+ '**How to use:** set the initial state with the `checked` attribute and read changes from the `kai-change` **CustomEvent** (payload `{ checked }`). The element self-manages its state.',
34
+ 'See the **Code** tab for HTML usage.',
35
+ ]),
36
+ },
37
+ },
38
+ } satisfies Meta;
39
+
40
+ export default meta;
41
+ type Story = StoryObj;
42
+
43
+ /** A self-managing toggle; logs each change. */
44
+ export const Default: Story = {
45
+ render: () => {
46
+ let el: HTMLElement | undefined;
47
+ onMount(() => el?.addEventListener('kai-change', (e) => console.log('kai-change', (e as CustomEvent<{ checked: boolean }>).detail.checked)));
48
+ return <kai-switch ref={(e) => (el = e as HTMLElement)} label="Temporary chat" style={{ display: 'inline-block', padding: '40px' }} />;
49
+ },
50
+ parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
51
+ };
52
+
53
+ /** Starts on via the bare `checked` attribute. */
54
+ export const On: Story = {
55
+ render: () => <kai-switch checked label="Notifications" style={{ display: 'inline-block', padding: '40px' }} />,
56
+ };
@@ -0,0 +1,43 @@
1
+ import { defineWebComponent } from './define';
2
+ import { Switch } from '../ui/switch';
3
+
4
+ interface Props extends Record<string, unknown> {
5
+ /** Initial checked state. Bare attribute (`<kai-switch checked>`) turns it on. */
6
+ checked?: boolean;
7
+ /** Disable interaction. */
8
+ disabled?: boolean;
9
+ /** Accessible label. */
10
+ label?: string;
11
+ }
12
+
13
+ /** Events fired by `<kai-switch>`. */
14
+ interface Events {
15
+ /** The toggle changed. */
16
+ 'kai-change': { checked: boolean };
17
+ }
18
+
19
+ /**
20
+ * `<kai-switch>` — a toggle switch. Self-manages its on/off state; set the initial
21
+ * state with the `checked` attribute and read changes from `kai-change`.
22
+ *
23
+ * ```html
24
+ * <kai-switch checked label="Temporary chat"></kai-switch>
25
+ * <script type="module">
26
+ * import '@kitn.ai/ui/elements';
27
+ * document.querySelector('kai-switch')
28
+ * .addEventListener('kai-change', (e) => console.log(e.detail.checked));
29
+ * </script>
30
+ * ```
31
+ */
32
+ defineWebComponent<Props, Events>('kai-switch', {
33
+ checked: undefined,
34
+ disabled: undefined,
35
+ label: undefined,
36
+ }, (props, { dispatch, flag }) => (
37
+ <Switch
38
+ defaultChecked={flag('checked')}
39
+ disabled={flag('disabled')}
40
+ label={props.label as string | undefined}
41
+ onChange={(checked) => dispatch('kai-change', { checked })}
42
+ />
43
+ ));