@kitn.ai/ui 0.15.0 → 0.16.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 (366) hide show
  1. package/README.md +9 -0
  2. package/bin/mcp.js +22 -0
  3. package/dist/bash-InADTalH.js +6 -1
  4. package/dist/components/artifact.d.ts +58 -0
  5. package/dist/components/attachments.d.ts +67 -0
  6. package/dist/components/card-fallback.d.ts +10 -0
  7. package/dist/components/card-renderer.d.ts +13 -0
  8. package/dist/components/card.d.ts +28 -0
  9. package/dist/components/chain-of-thought.d.ts +29 -0
  10. package/dist/components/chat-container.d.ts +19 -0
  11. package/dist/components/chat-scope-picker.d.ts +9 -0
  12. package/dist/components/chat-thread.d.ts +93 -0
  13. package/dist/components/checkpoint.d.ts +20 -0
  14. package/dist/components/choice-card.d.ts +77 -0
  15. package/dist/components/code-block.d.ts +16 -0
  16. package/dist/components/confirm-card.d.ts +57 -0
  17. package/dist/components/context.d.ts +65 -0
  18. package/dist/components/conversation-item.d.ts +8 -0
  19. package/dist/components/conversation-list.d.ts +11 -0
  20. package/dist/components/embed.d.ts +21 -0
  21. package/dist/components/empty.d.ts +43 -0
  22. package/dist/components/feedback-bar.d.ts +45 -0
  23. package/dist/components/file-tree.d.ts +57 -0
  24. package/dist/components/file-upload.d.ts +16 -0
  25. package/dist/components/form-widgets.d.ts +31 -0
  26. package/dist/components/form.d.ts +103 -0
  27. package/dist/components/image.d.ts +12 -0
  28. package/dist/components/link-preview.d.ts +23 -0
  29. package/dist/components/loader.d.ts +60 -0
  30. package/dist/components/markdown.d.ts +8 -0
  31. package/dist/components/message-skills.d.ts +15 -0
  32. package/dist/components/message.d.ts +54 -0
  33. package/dist/components/model-switcher.d.ts +8 -0
  34. package/dist/components/prompt-input.d.ts +38 -0
  35. package/dist/components/prompt-suggestion.d.ts +13 -0
  36. package/dist/components/reasoning.d.ts +20 -0
  37. package/dist/components/response-stream.d.ts +14 -0
  38. package/dist/components/scroll-button.d.ts +7 -0
  39. package/dist/components/slash-command.d.ts +15 -0
  40. package/dist/components/source.d.ts +23 -0
  41. package/dist/components/tasks-card.d.ts +71 -0
  42. package/dist/components/text-shimmer.d.ts +9 -0
  43. package/dist/components/thinking-bar.d.ts +10 -0
  44. package/dist/components/tool.d.ts +16 -0
  45. package/dist/components/use-card-resolution.d.ts +12 -0
  46. package/dist/components/voice-input.d.ts +7 -0
  47. package/dist/core-AYMC6_lb.js +5874 -12
  48. package/dist/css-M7EaDHN_.js +6 -1
  49. package/dist/elements/artifact.d.ts +1 -0
  50. package/dist/elements/attachments.d.ts +1 -0
  51. package/dist/elements/card.d.ts +1 -0
  52. package/dist/elements/cards.d.ts +0 -0
  53. package/dist/elements/chain-of-thought.d.ts +13 -0
  54. package/dist/elements/chat-scope-picker.d.ts +1 -0
  55. package/dist/elements/chat-types.d.ts +41 -0
  56. package/dist/elements/chat-workspace.d.ts +1 -0
  57. package/dist/elements/chat.d.ts +1 -0
  58. package/dist/elements/checkpoint.d.ts +1 -0
  59. package/dist/elements/choice.d.ts +1 -0
  60. package/dist/elements/code-block.d.ts +1 -0
  61. package/dist/elements/confirm-card.d.ts +1 -0
  62. package/dist/elements/context-meter.d.ts +1 -0
  63. package/dist/elements/conversation-list.d.ts +11 -0
  64. package/dist/elements/css.d.ts +1 -0
  65. package/dist/elements/default-input.d.ts +40 -0
  66. package/dist/elements/define.d.ts +42 -0
  67. package/dist/elements/embed.d.ts +1 -0
  68. package/dist/elements/empty.d.ts +1 -0
  69. package/dist/elements/feedback-bar.d.ts +1 -0
  70. package/dist/elements/file-tree.d.ts +1 -0
  71. package/dist/elements/file-upload.d.ts +1 -0
  72. package/dist/elements/form.d.ts +1 -0
  73. package/dist/elements/image.d.ts +1 -0
  74. package/dist/elements/link-preview.d.ts +1 -0
  75. package/dist/elements/loader.d.ts +1 -0
  76. package/dist/elements/markdown.d.ts +1 -0
  77. package/dist/elements/message-skills.d.ts +17 -0
  78. package/dist/elements/message.d.ts +1 -0
  79. package/dist/elements/model-switcher.d.ts +11 -0
  80. package/dist/elements/popover.d.ts +1 -0
  81. package/dist/elements/prompt-input.d.ts +9 -0
  82. package/dist/elements/prompt-suggestions.d.ts +7 -0
  83. package/dist/elements/reasoning.d.ts +1 -0
  84. package/dist/elements/register-impl.d.ts +0 -0
  85. package/dist/elements/register.d.ts +3 -0
  86. package/dist/elements/remote.d.ts +1 -0
  87. package/dist/elements/resizable.d.ts +17 -0
  88. package/dist/elements/response-stream.d.ts +1 -0
  89. package/dist/elements/scroll-button.d.ts +1 -0
  90. package/dist/elements/source.d.ts +18 -0
  91. package/dist/elements/switch.d.ts +1 -0
  92. package/dist/elements/tasks.d.ts +1 -0
  93. package/dist/elements/text-shimmer.d.ts +1 -0
  94. package/dist/elements/thinking-bar.d.ts +1 -0
  95. package/dist/elements/tool.d.ts +1 -0
  96. package/dist/elements/voice-input.d.ts +1 -0
  97. package/dist/elements.d.ts +732 -0
  98. package/dist/engine-javascript-vq0WuIJl.js +2516 -14
  99. package/dist/github-dark-dimmed-DUshB20C.js +4 -1
  100. package/dist/github-light-JYsPkUQd.js +4 -1
  101. package/dist/html-CPZ3oZQ7.js +10 -1
  102. package/dist/index.d.ts +112 -2
  103. package/dist/index.js +13551 -0
  104. package/dist/javascript-C25yR2R2.js +6 -1
  105. package/dist/json-DxJze_jm.js +6 -1
  106. package/dist/kitn-chat.es.js +1 -77
  107. package/dist/llms/llms-full.txt +1 -1
  108. package/dist/llms/llms.txt +1 -1
  109. package/dist/mcp.es.js +2140 -0
  110. package/dist/primitives/card-contract.d.ts +103 -0
  111. package/dist/primitives/card-host.d.ts +12 -0
  112. package/dist/primitives/card-registry.d.ts +17 -0
  113. package/dist/primitives/card-resolution.d.ts +8 -0
  114. package/dist/primitives/card-routing.d.ts +12 -0
  115. package/dist/primitives/card-validate.d.ts +25 -0
  116. package/dist/primitives/chat-config.d.ts +31 -0
  117. package/dist/primitives/controllable.d.ts +13 -0
  118. package/dist/primitives/embed-providers.d.ts +65 -0
  119. package/dist/primitives/highlighter.d.ts +23 -0
  120. package/dist/primitives/link-preview.d.ts +47 -0
  121. package/dist/primitives/pdf-preview.d.ts +50 -0
  122. package/dist/primitives/use-auto-resize.d.ts +8 -0
  123. package/dist/primitives/use-resize-observer.d.ts +1 -0
  124. package/dist/primitives/use-stick-to-bottom.d.ts +5 -0
  125. package/dist/primitives/use-text-stream.d.ts +19 -0
  126. package/dist/primitives/use-voice-recorder.d.ts +9 -0
  127. package/dist/react/index.d.ts +1118 -0
  128. package/dist/react/runtime.d.ts +15 -0
  129. package/dist/react.js +265 -0
  130. package/dist/register-impl-wCsFPoh9.js +77 -0
  131. package/dist/register-ujhr1nBS.js +1 -0
  132. package/dist/remote/host-embed.d.ts +33 -0
  133. package/dist/remote/index.d.ts +2 -0
  134. package/dist/remote/origin.d.ts +5 -0
  135. package/dist/remote/provider-runtime.d.ts +27 -0
  136. package/dist/remote/provider.d.ts +2 -0
  137. package/dist/remote/validate.d.ts +4 -0
  138. package/dist/remote/version.d.ts +4 -0
  139. package/dist/remote/wire.d.ts +53 -0
  140. package/dist/svelte--5p79yCD.js +15 -1
  141. package/dist/tsx-B8rCNbgL.js +6 -1
  142. package/dist/types.d.ts +42 -0
  143. package/dist/typescript-RycA9KXf.js +6 -1
  144. package/dist/ui/action-icons.d.ts +11 -0
  145. package/dist/ui/avatar.d.ts +8 -0
  146. package/dist/ui/badge.d.ts +9 -0
  147. package/dist/ui/button.d.ts +10 -0
  148. package/dist/ui/collapsible.d.ts +27 -0
  149. package/dist/ui/dropdown.d.ts +20 -0
  150. package/dist/ui/hover-card.d.ts +28 -0
  151. package/dist/ui/overlay.d.ts +67 -0
  152. package/dist/ui/popover.d.ts +32 -0
  153. package/dist/ui/resizable.d.ts +76 -0
  154. package/dist/ui/scroll-area.d.ts +5 -0
  155. package/dist/ui/separator.d.ts +5 -0
  156. package/dist/ui/skeleton.d.ts +5 -0
  157. package/dist/ui/switch.d.ts +19 -0
  158. package/dist/ui/textarea.d.ts +6 -0
  159. package/dist/ui/tooltip.d.ts +8 -0
  160. package/dist/utils/cn.d.ts +2 -0
  161. package/dist/vue-BmIZj4XD.js +33 -1
  162. package/frameworks/react/index.tsx +4 -0
  163. package/frameworks/react/runtime.tsx +16 -2
  164. package/llms-full.txt +1 -1
  165. package/llms.txt +1 -1
  166. package/package.json +29 -11
  167. package/src/agent-tooling/archetypes.ts +46 -0
  168. package/src/agent-tooling/integrations/cloudflare.ts +88 -0
  169. package/src/agent-tooling/integrations/langgraph.ts +60 -0
  170. package/src/agent-tooling/integrations/mastra.ts +27 -0
  171. package/src/agent-tooling/integrations/mock.ts +34 -0
  172. package/src/agent-tooling/integrations/ollama.ts +47 -0
  173. package/src/agent-tooling/integrations/openrouter.ts +26 -0
  174. package/src/agent-tooling/integrations/pi.ts +40 -0
  175. package/src/agent-tooling/integrations/pydantic-ai.ts +52 -0
  176. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +44 -0
  177. package/src/agent-tooling/mcp/manifest.ts +128 -0
  178. package/src/agent-tooling/mcp/server.ts +59 -0
  179. package/src/agent-tooling/mcp/stdio.ts +18 -0
  180. package/src/agent-tooling/mcp/tools/debug.ts +305 -0
  181. package/src/agent-tooling/mcp/tools/reference.ts +132 -0
  182. package/src/agent-tooling/mcp/tools/scaffold.ts +1627 -0
  183. package/src/agent-tooling/mcp/tools/theme.ts +340 -0
  184. package/src/agent-tooling/mcp/tools/types.ts +14 -0
  185. package/src/agent-tooling/registry.ts +41 -0
  186. package/src/agent-tooling/types.ts +30 -0
  187. package/src/elements/compiled.css +1 -1
  188. package/src/elements/define.tsx +7 -1
  189. package/src/elements/element-types.d.ts +2 -1
  190. package/src/elements/register-impl.ts +55 -0
  191. package/src/elements/register.ts +17 -51
  192. package/theme.css +4 -2
  193. package/src/components/artifact.stories.tsx +0 -138
  194. package/src/components/attachments.stories.tsx +0 -303
  195. package/src/components/attachments.test.tsx +0 -64
  196. package/src/components/chain-of-thought.stories.tsx +0 -211
  197. package/src/components/chat-container.stories.tsx +0 -187
  198. package/src/components/chat-thread.test.tsx +0 -58
  199. package/src/components/checkpoint.stories.tsx +0 -102
  200. package/src/components/code-block.stories.tsx +0 -150
  201. package/src/components/confirm-card.stories.tsx +0 -74
  202. package/src/components/context.stories.tsx +0 -229
  203. package/src/components/context.test.tsx +0 -133
  204. package/src/components/conversation-item.stories.tsx +0 -125
  205. package/src/components/conversation-list.stories.tsx +0 -133
  206. package/src/components/default-input.test.tsx +0 -111
  207. package/src/components/empty.stories.tsx +0 -434
  208. package/src/components/feedback-bar.stories.tsx +0 -138
  209. package/src/components/feedback-bar.test.tsx +0 -103
  210. package/src/components/file-tree.stories.tsx +0 -73
  211. package/src/components/file-upload.stories.tsx +0 -156
  212. package/src/components/image.stories.tsx +0 -89
  213. package/src/components/loader.stories.tsx +0 -181
  214. package/src/components/markdown.stories.tsx +0 -180
  215. package/src/components/message-action-bar.test.tsx +0 -128
  216. package/src/components/message-narrow.stories.tsx +0 -329
  217. package/src/components/message-skills.stories.tsx +0 -211
  218. package/src/components/message.stories.tsx +0 -281
  219. package/src/components/model-switcher.stories.tsx +0 -123
  220. package/src/components/model-switcher.test.tsx +0 -65
  221. package/src/components/prompt-input.stories.tsx +0 -222
  222. package/src/components/prompt-suggestion.stories.tsx +0 -142
  223. package/src/components/reasoning.stories.tsx +0 -140
  224. package/src/components/resizable.test.tsx +0 -226
  225. package/src/components/scroll-button.stories.tsx +0 -100
  226. package/src/components/slash-command.stories.tsx +0 -163
  227. package/src/components/source-list.test.tsx +0 -152
  228. package/src/components/source.stories.tsx +0 -124
  229. package/src/components/tasks-card.stories.tsx +0 -78
  230. package/src/components/text-shimmer.stories.tsx +0 -87
  231. package/src/components/thinking-bar.stories.tsx +0 -87
  232. package/src/components/tool.stories.tsx +0 -153
  233. package/src/components/voice-input.stories.tsx +0 -83
  234. package/src/elements/artifact.stories.tsx +0 -506
  235. package/src/elements/attachments.stories.tsx +0 -190
  236. package/src/elements/card.stories.tsx +0 -113
  237. package/src/elements/cards.stories.tsx +0 -59
  238. package/src/elements/catalog.stories.tsx +0 -491
  239. package/src/elements/chain-of-thought.declarative.test.tsx +0 -153
  240. package/src/elements/chain-of-thought.stories.tsx +0 -113
  241. package/src/elements/chat-scope-picker.stories.tsx +0 -73
  242. package/src/elements/chat-workspace.stories.tsx +0 -288
  243. package/src/elements/chat.stories.tsx +0 -151
  244. package/src/elements/checkpoint.stories.tsx +0 -72
  245. package/src/elements/choice.stories.tsx +0 -240
  246. package/src/elements/code-block.stories.tsx +0 -83
  247. package/src/elements/composed-shell.stories.tsx +0 -316
  248. package/src/elements/confirm-card.stories.tsx +0 -227
  249. package/src/elements/context-meter.stories.tsx +0 -151
  250. package/src/elements/conversation-list.declarative.test.tsx +0 -137
  251. package/src/elements/conversation-list.stories.tsx +0 -243
  252. package/src/elements/embed.stories.tsx +0 -213
  253. package/src/elements/empty.stories.tsx +0 -111
  254. package/src/elements/feedback-bar.stories.tsx +0 -114
  255. package/src/elements/file-tree.stories.tsx +0 -134
  256. package/src/elements/file-upload.stories.tsx +0 -82
  257. package/src/elements/form.stories.tsx +0 -248
  258. package/src/elements/image.stories.tsx +0 -71
  259. package/src/elements/link-preview.stories.tsx +0 -209
  260. package/src/elements/loader.stories.tsx +0 -88
  261. package/src/elements/markdown.stories.tsx +0 -76
  262. package/src/elements/message-skills.declarative.test.tsx +0 -104
  263. package/src/elements/message-skills.stories.tsx +0 -114
  264. package/src/elements/message.stories.tsx +0 -218
  265. package/src/elements/model-switcher.declarative.test.tsx +0 -130
  266. package/src/elements/model-switcher.stories.tsx +0 -198
  267. package/src/elements/popover.stories.tsx +0 -80
  268. package/src/elements/prompt-input-slash-command.test.tsx +0 -128
  269. package/src/elements/prompt-input-stoppable.test.tsx +0 -88
  270. package/src/elements/prompt-input-toolbar-actions.test.tsx +0 -120
  271. package/src/elements/prompt-input.stories.tsx +0 -331
  272. package/src/elements/prompt-suggestions.declarative.test.tsx +0 -164
  273. package/src/elements/prompt-suggestions.stories.tsx +0 -213
  274. package/src/elements/reasoning.stories.tsx +0 -77
  275. package/src/elements/remote.stories.tsx +0 -314
  276. package/src/elements/resizable.stories.tsx +0 -426
  277. package/src/elements/response-stream.stories.tsx +0 -79
  278. package/src/elements/scroll-button.stories.tsx +0 -202
  279. package/src/elements/scroll-button.test.tsx +0 -148
  280. package/src/elements/source-list.stories.tsx +0 -143
  281. package/src/elements/source.stories.tsx +0 -88
  282. package/src/elements/switch.stories.tsx +0 -56
  283. package/src/elements/tasks.stories.tsx +0 -237
  284. package/src/elements/text-shimmer.stories.tsx +0 -64
  285. package/src/elements/thinking-bar.stories.tsx +0 -72
  286. package/src/elements/tool.stories.tsx +0 -89
  287. package/src/elements/voice-input.stories.tsx +0 -88
  288. package/src/primitives/controllable.test.ts +0 -47
  289. package/src/stories/chat-panel-layout.stories.tsx +0 -145
  290. package/src/stories/chat-scene.tsx +0 -571
  291. package/src/stories/checkpoint-restore.stories.tsx +0 -256
  292. package/src/stories/context-usage.stories.tsx +0 -212
  293. package/src/stories/conversation-with-reasoning.stories.tsx +0 -182
  294. package/src/stories/conversation-with-sources.stories.tsx +0 -471
  295. package/src/stories/docs/Accessibility.mdx +0 -119
  296. package/src/stories/docs/ChildElements.mdx +0 -269
  297. package/src/stories/docs/ForAIAgents.mdx +0 -162
  298. package/src/stories/docs/GettingStarted.mdx +0 -65
  299. package/src/stories/docs/Installation.mdx +0 -83
  300. package/src/stories/docs/Introduction.mdx +0 -50
  301. package/src/stories/docs/SolidJsAdvanced.mdx +0 -17
  302. package/src/stories/docs/Theming.mdx +0 -85
  303. package/src/stories/docs/element-controls.ts +0 -121
  304. package/src/stories/docs/frameworks/Angular.mdx +0 -245
  305. package/src/stories/docs/frameworks/Html.mdx +0 -227
  306. package/src/stories/docs/frameworks/Overview.mdx +0 -47
  307. package/src/stories/docs/frameworks/React.mdx +0 -227
  308. package/src/stories/docs/frameworks/Solid.mdx +0 -173
  309. package/src/stories/docs/frameworks/Svelte.mdx +0 -194
  310. package/src/stories/docs/frameworks/Vue.mdx +0 -238
  311. package/src/stories/docs/generative-ui-overview.mdx +0 -186
  312. package/src/stories/docs/recipes/SpeechToText.mdx +0 -7
  313. package/src/stories/docs/recipes/Streaming.mdx +0 -68
  314. package/src/stories/docs/recipes/TextToSpeech.mdx +0 -35
  315. package/src/stories/docs/theme-editor/canvas.tsx +0 -32
  316. package/src/stories/docs/theme-editor/inspector.tsx +0 -66
  317. package/src/stories/docs/theme-editor/presets.test.ts +0 -32
  318. package/src/stories/docs/theme-editor/presets.ts +0 -64
  319. package/src/stories/docs/theme-editor/theme-css.test.ts +0 -19
  320. package/src/stories/docs/theme-editor/theme-css.ts +0 -15
  321. package/src/stories/docs/theme-editor/theme-editor.tsx +0 -146
  322. package/src/stories/docs/theme-tokens.tsx +0 -174
  323. package/src/stories/examples/ChoosingComponents.mdx +0 -106
  324. package/src/stories/examples/sample-data.ts +0 -79
  325. package/src/stories/examples/usage/checkpoint-restore.ts +0 -156
  326. package/src/stories/examples/usage/context-usage.ts +0 -591
  327. package/src/stories/examples/usage/conversation-with-reasoning.ts +0 -224
  328. package/src/stories/examples/usage/conversation-with-sources.ts +0 -589
  329. package/src/stories/examples/usage/empty-state.ts +0 -144
  330. package/src/stories/examples/usage/full-chat-app.ts +0 -277
  331. package/src/stories/examples/usage/index.ts +0 -63
  332. package/src/stories/examples/usage/message-actions.ts +0 -704
  333. package/src/stories/examples/usage/pattern-centered-conversation.ts +0 -446
  334. package/src/stories/examples/usage/pattern-chat-panel-layout.ts +0 -442
  335. package/src/stories/examples/usage/pattern-docked-widget.ts +0 -479
  336. package/src/stories/examples/usage/prompt-input-variants.ts +0 -1356
  337. package/src/stories/examples/usage/streaming-response.ts +0 -687
  338. package/src/stories/examples/usage/types.ts +0 -33
  339. package/src/stories/full-chat.stories.tsx +0 -18
  340. package/src/stories/message-actions.stories.tsx +0 -230
  341. package/src/stories/pattern-centered-conversation.stories.tsx +0 -93
  342. package/src/stories/pattern-docked-widget.stories.tsx +0 -93
  343. package/src/stories/pattern-empty-state.stories.tsx +0 -76
  344. package/src/stories/prompt-input-variants.stories.tsx +0 -456
  345. package/src/stories/streaming-response.stories.tsx +0 -438
  346. package/src/stories/theme-editor.stories.tsx +0 -16
  347. package/src/stories/token-reference.stories.tsx +0 -18
  348. package/src/stories/typography.stories.tsx +0 -78
  349. package/src/ui/avatar.stories.tsx +0 -103
  350. package/src/ui/badge.stories.tsx +0 -86
  351. package/src/ui/button.stories.tsx +0 -145
  352. package/src/ui/collapsible.stories.tsx +0 -69
  353. package/src/ui/dropdown.stories.tsx +0 -59
  354. package/src/ui/hover-card.stories.tsx +0 -77
  355. package/src/ui/hover-card.test.tsx +0 -30
  356. package/src/ui/overlay.stories.tsx +0 -115
  357. package/src/ui/popover.stories.tsx +0 -81
  358. package/src/ui/popover.test.tsx +0 -99
  359. package/src/ui/resizable.stories.tsx +0 -236
  360. package/src/ui/scroll-area.stories.tsx +0 -50
  361. package/src/ui/separator.stories.tsx +0 -81
  362. package/src/ui/skeleton.stories.tsx +0 -337
  363. package/src/ui/switch.stories.tsx +0 -51
  364. package/src/ui/switch.test.tsx +0 -59
  365. package/src/ui/textarea.stories.tsx +0 -76
  366. package/src/ui/tooltip.stories.tsx +0 -74
@@ -1,213 +0,0 @@
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
- type Item = string | { label: string; value?: string };
7
-
8
- // The web components are custom DOM elements, so declare the tags for JSX.
9
- declare module 'solid-js' {
10
- // eslint-disable-next-line @typescript-eslint/no-namespace
11
- namespace JSX {
12
- interface IntrinsicElements {
13
- 'kai-suggestions': JSX.HTMLAttributes<HTMLElement> & {
14
- variant?: string;
15
- size?: string;
16
- block?: boolean | string;
17
- highlight?: string;
18
- };
19
- /** Light-DOM data carrier for declarative suggestion chips inside `<kai-suggestions>`. */
20
- 'kai-suggestion': JSX.HTMLAttributes<HTMLElement> & {
21
- value?: string;
22
- };
23
- }
24
- }
25
- }
26
-
27
- const suggestions: Item[] = [
28
- 'Explain the architecture',
29
- 'Show me a code example',
30
- "What's deferred?",
31
- ];
32
-
33
- /** Render `<kai-suggestions>` with `suggestions` set as a property. */
34
- function SuggestionsElement(props: { suggestions: Item[]; variant?: string; size?: string; block?: boolean; highlight?: string }) {
35
- let el: (HTMLElement & { suggestions?: Item[] }) | undefined;
36
- onMount(() => {
37
- if (!el) return;
38
- el.suggestions = props.suggestions;
39
- el.addEventListener('kai-select', (e) => {
40
- const ev = e as CustomEvent<{ value: string }>;
41
- console.log('kai-select', ev.detail.value);
42
- });
43
- });
44
- return (
45
- <kai-suggestions
46
- ref={(e) => (el = e as HTMLElement)}
47
- variant={props.variant}
48
- size={props.size}
49
- block={props.block ? true : undefined}
50
- highlight={props.highlight}
51
- style={{ display: 'block', padding: '24px', 'max-width': '560px' }}
52
- />
53
- );
54
- }
55
-
56
- const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
57
- <kai-suggestions id="suggs" variant="outline"></kai-suggestions>
58
-
59
- <script type="module">
60
- import '@kitn.ai/ui/elements'; // registers the custom elements
61
-
62
- const suggs = document.getElementById('suggs');
63
- suggs.suggestions = ['Explain the architecture', 'Show me a code example'];
64
- suggs.addEventListener('kai-select', (e) => console.log(e.detail.value));
65
- </script>`;
66
-
67
- const meta = {
68
- title: 'Components/Suggestions',
69
- tags: ['autodocs'],
70
- argTypes: argTypesFor('kai-suggestions'),
71
- parameters: {
72
- layout: 'fullscreen',
73
- docs: {
74
- description: specDescription('kai-suggestions', [
75
- '`<kai-suggestions>` is the framework-agnostic **web component** for a row (or list) of clickable suggestion chips — starter prompts or follow-ups — isolated in **Shadow DOM**.',
76
- '**When to use:** offering the user quick prompts to click instead of type, usually above an input. In SolidJS, use the `PromptSuggestion` primitive.',
77
- '**Placement:** above the prompt input in the empty/welcome state, or below the last assistant message as follow-up chips; it is a `block` element and takes the full width of its container.',
78
- "**How to use:** register once with `import '@kitn.ai/ui/elements'`, set the `suggestions` **property** (strings, or `{ label, value }` when the displayed text differs from the emitted value), choose a `variant` and `size` (`sm` | `md` | `lg`; pills default to `lg`), optionally add the `block` flag for full-width rows or a `highlight` substring to emphasize, and listen for the `kai-select` **CustomEvent**.",
79
- 'See the **Code** tab for HTML usage.',
80
- ]),
81
- },
82
- },
83
- } satisfies Meta;
84
-
85
- export default meta;
86
- type Story = StoryObj;
87
-
88
- /** Default outline pills, wrapping in a row. */
89
- export const Default: Story = {
90
- render: () => <SuggestionsElement suggestions={suggestions} variant="outline" />,
91
- parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
92
- };
93
-
94
- /** Ghost variant. */
95
- export const Ghost: Story = {
96
- render: () => <SuggestionsElement suggestions={suggestions} variant="ghost" />,
97
- };
98
-
99
- /** Full-width left-aligned rows via the `block` flag. */
100
- export const Block: Story = {
101
- render: () => <SuggestionsElement suggestions={suggestions} variant="outline" block />,
102
- };
103
-
104
- const searchSuggestions: Item[] = [
105
- 'How does SolidJS handle reactivity?',
106
- 'What makes SolidJS fast?',
107
- 'SolidJS vs Svelte comparison',
108
- ];
109
-
110
- /** Filtered-search list: each row highlights the matched substring via the
111
- * `highlight` attribute (which forces the list-row layout). */
112
- export const WithHighlightedSearch: Story = {
113
- name: 'With Highlighted Search',
114
- render: () => (
115
- <SuggestionsElement suggestions={searchSuggestions} highlight="Solid" />
116
- ),
117
- parameters: {
118
- docs: {
119
- source: {
120
- code: `<kai-suggestions id="suggs" highlight="Solid"></kai-suggestions>
121
-
122
- <script type="module">
123
- import '@kitn.ai/ui/elements';
124
- const suggs = document.getElementById('suggs');
125
- suggs.suggestions = [
126
- 'How does SolidJS handle reactivity?',
127
- 'What makes SolidJS fast?',
128
- 'SolidJS vs Svelte comparison',
129
- ];
130
- </script>`,
131
- language: 'html',
132
- },
133
- },
134
- },
135
- };
136
-
137
- /** Sizes side by side — the default pill (`lg`) vs the smaller `sm` pill. */
138
- export const Sizes: Story = {
139
- render: () => (
140
- <div style={{ display: 'flex', 'flex-direction': 'column', gap: '8px', padding: '24px' }}>
141
- <div>
142
- <div style={{ 'font-size': '12px', opacity: '0.6', margin: '0 0 4px' }}>Default (lg)</div>
143
- <SuggestionsElement suggestions={suggestions} variant="outline" />
144
- </div>
145
- <div>
146
- <div style={{ 'font-size': '12px', opacity: '0.6', margin: '0 0 4px' }}>Small (sm)</div>
147
- <SuggestionsElement suggestions={suggestions} variant="outline" size="sm" />
148
- </div>
149
- </div>
150
- ),
151
- parameters: {
152
- docs: {
153
- source: {
154
- code: `<!-- default pill -->
155
- <kai-suggestions variant="outline"></kai-suggestions>
156
- <!-- smaller pill -->
157
- <kai-suggestions variant="outline" size="sm"></kai-suggestions>`,
158
- language: 'html',
159
- },
160
- },
161
- },
162
- };
163
-
164
- const DECLARATIVE_HTML_SNIPPET = `<!-- Works in any framework or plain HTML — no JS property assignment needed -->
165
- <kai-suggestions id="suggs" variant="outline">
166
- <kai-suggestion value="explain">Explain the architecture</kai-suggestion>
167
- <kai-suggestion value="example">Show me a code example</kai-suggestion>
168
- <kai-suggestion value="deferred">What's deferred?</kai-suggestion>
169
- </kai-suggestions>
170
-
171
- <script type="module">
172
- import '@kitn.ai/ui/elements'; // registers the custom elements
173
-
174
- document.getElementById('suggs').addEventListener('kai-select', (e) => {
175
- console.log('kai-select', e.detail.value);
176
- });
177
- </script>`;
178
-
179
- /**
180
- * Declare each suggestion as a `<kai-suggestion>` child element — no `suggestions`
181
- * property or JS array wiring needed. The `value` attribute sets the emitted
182
- * value; `textContent` is the displayed label. Children are light-DOM data
183
- * carriers hidden by the Shadow DOM — pure data, no visible output of their own.
184
- * Mix with the `suggestions` prop: prop items render first, declarative children after.
185
- */
186
- export const DeclarativeSuggestions: Story = {
187
- name: 'Declarative Suggestions (kai-suggestion)',
188
- render: () => {
189
- let el: HTMLElement | undefined;
190
- onMount(() => {
191
- if (!el) return;
192
- el.addEventListener('kai-select', (e) =>
193
- console.log('kai-select', (e as CustomEvent<{ value: string }>).detail.value),
194
- );
195
- });
196
- return (
197
- <kai-suggestions
198
- ref={(e) => (el = e as HTMLElement)}
199
- variant="outline"
200
- style={{ display: 'block', padding: '24px', 'max-width': '560px' }}
201
- >
202
- <kai-suggestion value="explain">Explain the architecture</kai-suggestion>
203
- <kai-suggestion value="example">Show me a code example</kai-suggestion>
204
- <kai-suggestion value="deferred">What's deferred?</kai-suggestion>
205
- </kai-suggestions>
206
- );
207
- },
208
- parameters: {
209
- docs: {
210
- source: { code: DECLARATIVE_HTML_SNIPPET, language: 'html' },
211
- },
212
- },
213
- };
@@ -1,77 +0,0 @@
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-reasoning': JSX.HTMLAttributes<HTMLElement>;
12
- }
13
- }
14
- }
15
-
16
- const sampleText =
17
- 'First I parse the request, then I plan the steps, then I execute and verify each one before responding.';
18
-
19
- /** Render the actual `<kai-reasoning>` custom element with a `text` property. */
20
- function ReasoningElement(props: { text: string; streaming?: boolean }) {
21
- let el: (HTMLElement & { text?: string; streaming?: boolean }) | undefined;
22
- onMount(() => {
23
- if (el) {
24
- el.text = props.text;
25
- if (props.streaming) el.streaming = true;
26
- }
27
- });
28
- return (
29
- <kai-reasoning ref={(e) => (el = e as HTMLElement)} style={{ display: 'block', padding: '16px', 'max-width': '720px' }} />
30
- );
31
- }
32
-
33
- const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
34
- <kai-reasoning id="reason" label="Reasoning"></kai-reasoning>
35
-
36
- <script type="module">
37
- import '@kitn.ai/ui/elements'; // registers the custom elements
38
-
39
- const reason = document.getElementById('reason');
40
- reason.text = 'First I parse the request, then I plan the steps, then I execute.';
41
- // reason.streaming = true; // auto-expands while a thought streams in
42
-
43
- // events are CustomEvents on the element (they do not bubble)
44
- reason.addEventListener('kai-open-change', (e) => console.log('open:', e.detail.open));
45
- </script>`;
46
-
47
- const meta = {
48
- title: 'Components/Reasoning',
49
- tags: ['autodocs'],
50
- argTypes: argTypesFor('kai-reasoning'),
51
- parameters: {
52
- layout: 'fullscreen',
53
- docs: {
54
- description: specDescription('kai-reasoning', [
55
- '`<kai-reasoning>` is the framework-agnostic **web component** for a collapsible reasoning/thinking block that auto-expands while a thought is `streaming`, isolated in **Shadow DOM**.',
56
- '**When to use:** surfacing model chain-of-thought in a non-Solid app. In SolidJS, compose the `Reasoning` primitives directly.',
57
- '**Placement:** inline inside an assistant message row, between the content and any tool calls; renders as a block sized to its content.',
58
- "**How to use:** register once with `import '@kitn.ai/ui/elements'`, set the body via the `text` **property**, set the `streaming` flag while it streams in, optionally drive the controlled `open` property, and listen for the `kai-open-change` **CustomEvent**.",
59
- 'See the **Code** tab for HTML usage.',
60
- ]),
61
- },
62
- },
63
- } satisfies Meta;
64
-
65
- export default meta;
66
- type Story = StoryObj;
67
-
68
- /** A collapsed reasoning block (the trigger toggles it). */
69
- export const Default: Story = {
70
- render: () => <ReasoningElement text={sampleText} />,
71
- parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
72
- };
73
-
74
- /** With `streaming` set, the block auto-expands. */
75
- export const Streaming: Story = {
76
- render: () => <ReasoningElement text={sampleText} streaming />,
77
- };
@@ -1,314 +0,0 @@
1
- import type { Meta, StoryObj } from 'storybook-solidjs-vite';
2
- import { createSignal, createEffect, onMount, onCleanup, type JSX } from 'solid-js';
3
- import './remote';
4
- import type { CardEnvelope, CardEvent, CardHost } from '../primitives/card-contract';
5
- import { formRenderer, infoRenderer } from '../../examples/remote-provider/renderers';
6
-
7
- declare module 'solid-js' {
8
- // eslint-disable-next-line @typescript-eslint/no-namespace
9
- namespace JSX {
10
- interface IntrinsicElements {
11
- 'kai-remote': JSX.HTMLAttributes<HTMLElement> & {
12
- src?: string;
13
- 'provider-origin'?: string;
14
- ref?: (el: HTMLElement) => void;
15
- };
16
- }
17
- }
18
- }
19
-
20
- type RemoteEl = HTMLElement & { envelope?: CardEnvelope; policy?: Record<string, unknown> };
21
-
22
- /**
23
- * The live cross-origin demo only works in **local Storybook dev** (`npm run storybook`):
24
- * there, `.storybook/main.ts`'s Vite pipeline serves the reference provider at
25
- * `/remote-provider/`, and we frame it via the `127.0.0.1` alias of the SAME dev server
26
- * — a genuinely different origin from the `localhost` preview, so `<kai-remote>`'s
27
- * cross-origin precondition (provider ≠ host) holds.
28
- *
29
- * A **static, single-origin deploy** (e.g. the GitHub Pages docs) cannot do this: there
30
- * is no second origin and the provider isn't served. So `liveProvider()` returns `null`
31
- * there and the stories render an explanatory panel instead of a doomed mount. The real
32
- * cross-origin behavior is verified by the standalone Playwright suite (H-L).
33
- */
34
- function liveProvider(): { origin: string; src: string } | null {
35
- if (typeof window === 'undefined') return null;
36
- // The deployed/built Storybook (PROD) is single-origin + has no provider middleware.
37
- if (import.meta.env.PROD) return null;
38
- const here = new URL(window.location.href);
39
- if ((here.hostname !== 'localhost' && here.hostname !== '127.0.0.1') || !here.port) return null;
40
- // Swap localhost ↔ 127.0.0.1 to obtain a cross-origin sibling of the dev server.
41
- const alias = here.hostname === '127.0.0.1' ? 'localhost' : '127.0.0.1';
42
- const origin = `${here.protocol}//${alias}:${here.port}`;
43
- return { origin, src: `${origin}/remote-provider/` };
44
- }
45
-
46
- const FORM_ENVELOPE: CardEnvelope = {
47
- type: 'form',
48
- id: 'remote-form-1',
49
- title: 'Quick question',
50
- data: {
51
- type: 'object',
52
- required: ['email'],
53
- properties: {
54
- email: { type: 'string', title: 'Email', format: 'email' },
55
- role: { type: 'string', title: 'Role', enum: ['Engineer', 'Designer', 'PM'] },
56
- },
57
- 'x-kai-submitLabel': 'Send',
58
- },
59
- };
60
-
61
- const WEATHER_ENVELOPE: CardEnvelope = {
62
- type: 'info',
63
- id: 'remote-info-1',
64
- title: 'San Francisco',
65
- data: {
66
- location: 'San Francisco',
67
- temperature: 18,
68
- unit: '°C',
69
- condition: 'Partly cloudy',
70
- humidity: 64,
71
- wind: 12,
72
- feelsLike: 17,
73
- forecast: [
74
- { day: 'Mon', high: 19, low: 12 },
75
- { day: 'Tue', high: 21, low: 13 },
76
- { day: 'Wed', high: 17, low: 11 },
77
- ],
78
- },
79
- };
80
-
81
- /** The Storybook theme mode, read the way the kit elements do (preview.ts mirrors
82
- * the resolved Storybook theme by toggling `.dark` on the <html>). Falls back to
83
- * the OS preference when not in the Storybook shell. */
84
- function readThemeMode(): 'light' | 'dark' {
85
- if (typeof document === 'undefined') return 'light';
86
- if (document.documentElement.classList.contains('dark')) return 'dark';
87
- if (document.documentElement.classList.contains('light')) return 'light';
88
- if (typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: dark)').matches) return 'dark';
89
- return 'light';
90
- }
91
-
92
- /** Pick the matching provider renderer for a card type (the SAME renderers the live
93
- * cross-origin provider registers), or null for an unhandled type. */
94
- function rendererFor(type: string) {
95
- if (type === 'form') return formRenderer;
96
- if (type === 'info') return infoRenderer;
97
- return null;
98
- }
99
-
100
- /** Mounts a <kai-remote> when a live cross-origin provider is available (local dev),
101
- * logs every routed CardEvent (via the bubbling kai-card). On a static/deployed
102
- * Storybook (no second origin) it renders the SAME provider renderer's output
103
- * DIRECTLY — so the docs show the real, interactive card — with a slim honest
104
- * banner explaining the production transport. */
105
- function RemoteDemo(props: { envelope: CardEnvelope; src?: string; providerOrigin?: string; showEnvelope?: boolean }) {
106
- const live = props.providerOrigin && props.src ? { origin: props.providerOrigin, src: props.src } : liveProvider();
107
- const [log, setLog] = createSignal<CardEvent[]>([]);
108
- const [mode, setMode] = createSignal<'light' | 'dark'>(readThemeMode());
109
- let el: RemoteEl | undefined;
110
- let container: HTMLDivElement | undefined;
111
-
112
- const renderer = rendererFor(props.envelope.type);
113
-
114
- // ── Live (local dev): cross-origin <kai-remote>, exactly as before. ──
115
- onMount(() => {
116
- if (!live || !el) return;
117
- el.envelope = props.envelope;
118
- const onCard = (e: Event) => {
119
- const detail = (e as CustomEvent<CardEvent>).detail;
120
- setLog((prev) => [...prev, detail]);
121
- };
122
- el.addEventListener('kai-card', onCard);
123
- onCleanup(() => el?.removeEventListener('kai-card', onCard));
124
- });
125
-
126
- // ── Static (deployed): render the real card content directly, reusing the
127
- // provider renderer. Re-mount when the theme mode changes so the ThemePush
128
- // story still means something on static. ──
129
- if (!live && renderer) {
130
- // Track Storybook's light/dark toggle (preview.ts flips `.dark` on <html>).
131
- onMount(() => {
132
- if (typeof MutationObserver === 'undefined') return;
133
- const obs = new MutationObserver(() => setMode(readThemeMode()));
134
- obs.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
135
- onCleanup(() => obs.disconnect());
136
- });
137
-
138
- createEffect(() => {
139
- const m = mode(); // re-run on theme change
140
- if (!container) return;
141
- const stubHost: CardHost = {
142
- context: () => ({ theme: { mode: m }, locale: 'en' }),
143
- emit: (e) => setLog((prev) => [...prev, e]),
144
- };
145
- const dispose = renderer.mount(container, props.envelope, stubHost);
146
- onCleanup(() => {
147
- try { dispose(); } catch { /* renderer disposer threw — best-effort */ }
148
- if (container) container.replaceChildren();
149
- });
150
- });
151
- }
152
-
153
- return (
154
- <div style={{ display: 'flex', gap: '16px', 'flex-wrap': 'wrap', 'align-items': 'flex-start' }}>
155
- <div style={{ flex: '1 1 320px', 'min-width': '300px', 'max-width': '460px' }}>
156
- {live ? (
157
- <kai-remote ref={(e) => (el = e as RemoteEl)} provider-origin={live.origin} src={live.src} />
158
- ) : renderer ? (
159
- <div style={{ display: 'flex', 'flex-direction': 'column', gap: '8px' }}>
160
- <div
161
- ref={(e) => (container = e)}
162
- style={{ border: '1px solid var(--color-border, #e4e4e7)', 'border-radius': '12px', overflow: 'hidden' }}
163
- />
164
- <p
165
- role="note"
166
- style={{ margin: 0, 'font-size': '12px', 'line-height': '1.5', color: 'var(--color-muted-foreground, #71717a)' }}
167
- >
168
- Rendered directly for these static docs. In production <code>&lt;kai-remote&gt;</code> delivers this over a
169
- sandboxed cross-origin iframe — run <code>npm run storybook</code> for the live transport; the cross-origin
170
- model is verified by the Playwright suite.
171
- </p>
172
- </div>
173
- ) : (
174
- <div
175
- role="note"
176
- style={{
177
- border: '1px dashed var(--color-border, #d4d4d8)', 'border-radius': '12px',
178
- padding: '16px', 'font-size': '13px', 'line-height': '1.55', color: 'var(--color-foreground, #18181b)',
179
- }}
180
- >
181
- <strong>Live cross-origin demo runs in local Storybook</strong>
182
- <p style={{ margin: '8px 0 0' }}>
183
- <code>&lt;kai-remote&gt;</code> delivers this card over a sandboxed{' '}
184
- <strong>cross-origin</strong> <code>&lt;iframe&gt;</code>, which needs a second
185
- origin and the reference provider served by the dev server. Run{' '}
186
- <code>npm run storybook</code> to see it live; the cross-origin transport is
187
- verified by the Playwright e2e matrix.
188
- </p>
189
- </div>
190
- )}
191
- </div>
192
- <div style={{ flex: '1 1 280px', 'min-width': '260px', display: 'flex', 'flex-direction': 'column', gap: '12px' }}>
193
- {props.showEnvelope && (
194
- <pre style={{ margin: 0, 'font-size': '12px', background: 'var(--color-muted, #f4f4f5)', 'border-radius': '8px', padding: '8px', overflow: 'auto' }}>
195
- {`// CardEnvelope sent down the wire (inside a WireFrame):\n` + JSON.stringify(props.envelope, null, 2)}
196
- </pre>
197
- )}
198
- <pre style={{ margin: 0, 'max-height': '200px', overflow: 'auto', background: 'var(--color-muted, #f4f4f5)', 'border-radius': '8px', padding: '8px', 'font-size': '12px' }}>
199
- {log().length === 0 ? '// routed CardEvents appear here' : JSON.stringify(log(), null, 2)}
200
- </pre>
201
- </div>
202
- </div>
203
- );
204
- }
205
-
206
- const HTML_SNIPPET = (envelope: CardEnvelope) => `<kai-remote
207
- provider-origin="https://cards.provider.example"
208
- src="https://cards.provider.example/card"
209
- ></kai-remote>
210
- <script type="module">
211
- import '@kitn.ai/ui/elements'; // registers <kai-remote>
212
-
213
- const el = document.querySelector('kai-remote');
214
- // The CardEnvelope is set as a JS PROPERTY (it travels down the wire unchanged).
215
- el.envelope = ${JSON.stringify(envelope, null, 2)};
216
-
217
- // Every routed CardEvent is re-emitted as a bubbling kai-card CustomEvent.
218
- el.addEventListener('kai-card', (e) => {
219
- if (e.detail.kind === 'submit') console.log('submitted', e.detail.data);
220
- });
221
-
222
- // Or pass a CardPolicy directly (same shape native cards use):
223
- // el.policy = { onSubmit: (cardId, data) => save(data) };
224
- </script>`;
225
-
226
- const meta = {
227
- title: 'Generative UI/Remote/kai-remote',
228
- tags: ['autodocs'],
229
- parameters: {
230
- layout: 'padded',
231
- // axe can't read a CROSS-ORIGIN frame's tree (that's the provider's a11y
232
- // obligation, proven by the provider's own stories/tests); scope axe to the
233
- // HOST page only — the iframe boundary + any inline fallback regions (H-L).
234
- a11y: { context: { exclude: [['iframe']] } },
235
- docs: {
236
- description: {
237
- component:
238
- "`<kai-remote>` mounts a **sandboxed cross-origin `<iframe>`** card from a card *provider* and bridges it to the host over `postMessage` — the SAME `CardEnvelope`/`CardContext`/`CardEvent` shapes as native cards, routed through the SAME `CardPolicy`. " +
239
- 'It pins the provider **origin + source window + a per-instance nonce + the negotiated protocol version** on every inbound frame, auto-sizes the iframe from the card’s reported height, pushes theme/locale context, and re-emits every routed event as a bubbling **`kai-card`** CustomEvent. ' +
240
- 'These stories frame the reference provider (`examples/remote-provider/`) served by Storybook over its `127.0.0.1` alias so the precondition (provider ≠ host origin) holds; the full cross-origin **security matrix** is the standalone Playwright suite.',
241
- },
242
- },
243
- },
244
- } satisfies Meta;
245
-
246
- export default meta;
247
- type Story = StoryObj;
248
-
249
- /** Happy path: the framed provider renders a `<kai-form>`; submitting it crosses the
250
- * origin boundary and the routed `submit` is logged. The CardEnvelope is shown too. */
251
- export const RemoteForm: Story = {
252
- name: 'Remote form (happy path)',
253
- render: () => <RemoteDemo envelope={FORM_ENVELOPE} showEnvelope />,
254
- parameters: { docs: { source: { code: HTML_SNIPPET(FORM_ENVELOPE), language: 'html' } } },
255
- };
256
-
257
- /** Auto-height: the self-contained card’s `<details>` forecast toggle grows the
258
- * content; the runtime reports a larger `resize` and the host enlarges the iframe. */
259
- export const AutoHeight: Story = {
260
- name: 'Auto-height',
261
- render: () => <RemoteDemo envelope={WEATHER_ENVELOPE} />,
262
- parameters: { docs: { source: { code: HTML_SNIPPET(WEATHER_ENVELOPE), language: 'html' } } },
263
- };
264
-
265
- /** Theme push: toggle the Storybook light/dark toolbar — the host re-pushes
266
- * `context` and the framed card re-themes live (no reload). */
267
- export const ThemePush: Story = {
268
- name: 'Theme push',
269
- render: () => <RemoteDemo envelope={WEATHER_ENVELOPE} />,
270
- parameters: { docs: { source: { code: HTML_SNIPPET(WEATHER_ENVELOPE), language: 'html' } } },
271
- };
272
-
273
- /** Self-contained display card: a rich, read-only weather view rendered entirely
274
- * from `envelope.data` inside the provider. It is internally interactive (the
275
- * forecast toggle) but emits NOTHING back to the host — the zero-round-trip
276
- * pattern. The bridge still auto-sizes it. */
277
- export const SelfContained: Story = {
278
- name: 'Self-contained display',
279
- render: () => <RemoteDemo envelope={WEATHER_ENVELOPE} showEnvelope />,
280
- parameters: { docs: { source: { code: HTML_SNIPPET(WEATHER_ENVELOPE), language: 'html' } } },
281
- };
282
-
283
- /** Failure: an invalid `provider-origin` (a wildcard) is rejected before any mount
284
- * — <kai-remote> renders an inline accessible error instead of an iframe. (A bad
285
- * `src` that loads but never handshakes shows the SDK’s inline fallback + Retry;
286
- * that path is exercised end-to-end by the Playwright suite.) */
287
- export const Failure: Story = {
288
- name: 'Failure: bad provider-origin',
289
- render: () => {
290
- let el: RemoteEl | undefined;
291
- onMount(() => {
292
- if (el) el.envelope = FORM_ENVELOPE;
293
- });
294
- return (
295
- <div style={{ 'max-width': '460px' }}>
296
- <kai-remote ref={(e) => (el = e as RemoteEl)} provider-origin="*" src="https://cards.provider.example/card" />
297
- </div>
298
- );
299
- },
300
- parameters: {
301
- docs: {
302
- source: {
303
- code: `<!-- provider-origin must be a single absolute origin (https, or http://localhost for dev). -->
304
- <kai-remote provider-origin="*" src="https://cards.provider.example/card"></kai-remote>
305
- <script type="module">
306
- import '@kitn.ai/ui/elements';
307
- document.querySelector('kai-remote').envelope = ${JSON.stringify(FORM_ENVELOPE, null, 2)};
308
- // "*" is rejected → an inline accessible error renders instead of an iframe.
309
- </script>`,
310
- language: 'html',
311
- },
312
- },
313
- },
314
- };