@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,237 +0,0 @@
1
- import type { Meta, StoryObj } from 'storybook-solidjs-vite';
2
- import { createSignal, onMount, type JSX } from 'solid-js';
3
- import './tasks';
4
- import { argTypesFor, specDescription } from '../stories/docs/element-controls';
5
- import type { TasksCardData } from '../components/tasks-card';
6
- import type { CardEvent } from '../primitives/card-contract';
7
-
8
- declare module 'solid-js' {
9
- // eslint-disable-next-line @typescript-eslint/no-namespace
10
- namespace JSX {
11
- interface IntrinsicElements {
12
- 'kai-tasks': JSX.HTMLAttributes<HTMLElement> & {
13
- heading?: string;
14
- 'card-id'?: string;
15
- ref?: (el: HTMLElement) => void;
16
- };
17
- }
18
- }
19
- }
20
-
21
- type TasksEl = HTMLElement & { data?: TasksCardData; resolution?: Record<string, unknown> };
22
-
23
- function Frame(props: { children: JSX.Element }) {
24
- return <div style={{ 'max-width': '460px' }}>{props.children}</div>;
25
- }
26
-
27
- /** Mounts a <kai-tasks>, sets `.data`, logs the emitted CardEvent under the render. */
28
- function TasksDemo(props: { def: TasksCardData; cardId: string; heading?: string }) {
29
- const [log, setLog] = createSignal<CardEvent[]>([]);
30
- let el: TasksEl | undefined;
31
- onMount(() => {
32
- if (!el) return;
33
- el.data = props.def;
34
- el.addEventListener('kai-card', (e) => {
35
- const detail = (e as CustomEvent<CardEvent>).detail;
36
- setLog((prev) => [...prev, detail]);
37
- });
38
- });
39
- return (
40
- <Frame>
41
- <div style={{ display: 'flex', 'flex-direction': 'column', gap: '12px' }}>
42
- <kai-tasks ref={(e) => (el = e as TasksEl)} card-id={props.cardId} heading={props.heading} />
43
- <pre
44
- style={{
45
- margin: 0,
46
- 'max-height': '180px',
47
- overflow: 'auto',
48
- background: 'var(--color-muted, #f4f4f5)',
49
- 'border-radius': '8px',
50
- padding: '8px',
51
- 'font-size': '12px',
52
- }}
53
- >
54
- {log().length === 0 ? '// emitted CardEvents appear here' : JSON.stringify(log(), null, 2)}
55
- </pre>
56
- </div>
57
- </Frame>
58
- );
59
- }
60
-
61
- const PLAN: TasksCardData = {
62
- mode: 'select',
63
- selectAll: true,
64
- confirmLabel: 'Run selected',
65
- tasks: [
66
- { id: 'lint', label: 'Run linter', checked: true },
67
- { id: 'test', label: 'Run unit tests', checked: true },
68
- { id: 'build', label: 'Build production bundle' },
69
- { id: 'deploy', label: 'Deploy to staging', description: 'Reversible; staging only' },
70
- ],
71
- };
72
-
73
- const REQUIRE_ONE: TasksCardData = {
74
- confirmLabel: 'Apply',
75
- allowEmpty: false,
76
- tasks: [
77
- { id: 'cache', label: 'Clear the CDN cache' },
78
- { id: 'reindex', label: 'Rebuild the search index' },
79
- { id: 'restart', label: 'Restart the workers' },
80
- ],
81
- };
82
-
83
- const BOUNDED: TasksCardData = {
84
- heading: 'Pick up to 2 reviewers',
85
- confirmLabel: 'Request review',
86
- min: 1,
87
- max: 2,
88
- tasks: [
89
- { id: 'ana', label: 'Ana' },
90
- { id: 'ben', label: 'Ben' },
91
- { id: 'cat', label: 'Cat' },
92
- { id: 'dan', label: 'Dan' },
93
- ],
94
- };
95
-
96
- const WITH_DESCRIPTIONS: TasksCardData = {
97
- selectAll: true,
98
- confirmLabel: 'Run cleanup',
99
- tasks: [
100
- { id: 'tmp', label: 'Delete temp files', description: 'Frees ~2.1 GB; safe to remove' },
101
- { id: 'logs', label: 'Rotate logs', description: 'Archives logs older than 30 days' },
102
- { id: 'orphans', label: 'Prune orphaned blobs', description: 'Unreferenced uploads only' },
103
- ],
104
- };
105
-
106
- const HEADING_MAP: Record<string, string | undefined> = {
107
- 'card-plan': 'Approve the plan steps',
108
- 'card-require': 'Choose maintenance steps',
109
- 'card-bounded': undefined,
110
- 'card-desc': 'Storage cleanup',
111
- };
112
-
113
- const HTML_SNIPPET = (def: TasksCardData, cardId: string) => {
114
- const heading = HEADING_MAP[cardId];
115
- return `<kai-tasks${heading ? ` heading="${heading}"` : ''}></kai-tasks>
116
- <script type="module">
117
- import '@kitn.ai/ui/elements'; // registers the custom elements
118
-
119
- const el = document.querySelector('kai-tasks');
120
- // \`data\` is the CardEnvelope.data (set as a property).
121
- el.data = ${JSON.stringify(def, null, 2)};
122
-
123
- // Toggling rows is local; only CONFIRM emits — a single bubbling \`kai-card\` event.
124
- el.addEventListener('kai-card', (e) => {
125
- const ev = e.detail; // { kind:'submit', cardId, data:{ selected } } | ...
126
- if (ev.kind === 'submit') console.log('selected', ev.data.selected);
127
- });
128
- </script>`;
129
- };
130
-
131
- const meta = {
132
- title: 'Generative UI/Cards/kai-tasks',
133
- tags: ['autodocs'],
134
- argTypes: argTypesFor('kai-tasks'),
135
- parameters: {
136
- layout: 'padded',
137
- docs: {
138
- description: specDescription('kai-tasks', [
139
- "`<kai-tasks>` is a **selectable** task/plan list (set via the `data` **property**): checkbox rows + an optional select-all + a confirm button. The user picks a subset, confirms, and the card emits the Card contract's **`submit`** verb up a bubbling **`kai-card`** CustomEvent of `{ kind: 'submit', cardId, data: { selected } }` — the checked ids in **input order**. Toggling rows is local UI state; **only the final confirm emits** (the wire stays quiet, the result atomic).",
140
- '**Anatomy:** `<kai-card>` chrome (optional heading) → **select-all row** (shown when `selectAll:true` and ≥2 toggleable tasks; indeterminate state when partially checked) → **task rows** (one per `tasks[]` item: checkbox + label + optional description; disabled when `max` reached or `task.disabled`) → **card footer** (selected-count label + confirm `<Button>`, disabled until gating passes; replaced by a read-only resolved summary after submission).',
141
- '**Gating:** confirm is enabled when `selectedCount >= (min ?? (allowEmpty ? 0 : 1))` and `<= (max ?? ∞)`. Select-all checks every toggleable (non-`disabled`) row and shows an **indeterminate** (`aria-checked="mixed"`) state when only some are checked. When `max` is reached, unchecked rows become non-toggleable. v1 is **select/approve only** (a future `mode:\'progress\'` is reserved in the schema).',
142
- '**Events** (all frozen Card-contract verbs): `ready` on mount, `submit` on confirm, `error` for a malformed definition (renders the inline `kai-card` error). It **never invents events**. The same shapes flow over the remote iframe transport unchanged.',
143
- ]),
144
- },
145
- },
146
- } satisfies Meta;
147
-
148
- export default meta;
149
- type Story = StoryObj;
150
-
151
- /** Select a plan (select-all on, a few pre-checked). */
152
- export const SelectAPlan: Story = {
153
- render: () => <TasksDemo def={PLAN} cardId="card-plan" heading="Approve the plan steps" />,
154
- parameters: { docs: { source: { code: HTML_SNIPPET(PLAN, 'card-plan'), language: 'html' } } },
155
- };
156
-
157
- /** Require at least one (`allowEmpty:false`, the default) — confirm stays disabled until a row is checked. */
158
- export const RequireAtLeastOne: Story = {
159
- render: () => <TasksDemo def={REQUIRE_ONE} cardId="card-require" heading="Choose maintenance steps" />,
160
- parameters: { docs: { source: { code: HTML_SNIPPET(REQUIRE_ONE, 'card-require'), language: 'html' } } },
161
- };
162
-
163
- /** Bounded (`min`/`max`) — confirm gating + max-reached row disabling. */
164
- export const Bounded: Story = {
165
- render: () => <TasksDemo def={BOUNDED} cardId="card-bounded" />,
166
- parameters: { docs: { source: { code: HTML_SNIPPET(BOUNDED, 'card-bounded'), language: 'html' } } },
167
- };
168
-
169
- /** Rows with secondary descriptions (linked via aria-describedby). */
170
- export const WithDescriptions: Story = {
171
- render: () => <TasksDemo def={WITH_DESCRIPTIONS} cardId="card-desc" heading="Storage cleanup" />,
172
- parameters: { docs: { source: { code: HTML_SNIPPET(WITH_DESCRIPTIONS, 'card-desc'), language: 'html' } } },
173
- };
174
-
175
- const RESOLVED_TASKS: TasksCardData = {
176
- confirmLabel: 'Export',
177
- tasks: [
178
- { id: 'sum', label: 'Executive summary' },
179
- { id: 'data', label: 'Raw data' },
180
- { id: 'charts', label: 'Charts' },
181
- ],
182
- };
183
-
184
- /** The card after the user confirmed their selection — shows "Selected 2 of 3", no checkboxes or button. */
185
- export const Resolved: Story = {
186
- name: 'Resolved (read-only)',
187
- render: () => {
188
- let el: TasksEl | undefined;
189
- onMount(() => {
190
- if (!el) return;
191
- el.data = RESOLVED_TASKS;
192
- el.resolution = { kind: 'submit', data: { selected: ['sum', 'charts'] } };
193
- });
194
- return (
195
- <Frame>
196
- <kai-tasks ref={(e) => (el = e as TasksEl)} card-id="card-resolved-tasks" heading="Export report" />
197
- </Frame>
198
- );
199
- },
200
- parameters: {
201
- docs: {
202
- source: {
203
- code: `<kai-tasks heading="Export report"></kai-tasks>
204
- <script type="module">
205
- import '@kitn.ai/ui/elements';
206
- const el = document.querySelector('kai-tasks');
207
- el.data = ${JSON.stringify(RESOLVED_TASKS, null, 2)};
208
- // Setting .resolution renders the chromed read-only view — no checkboxes or confirm button.
209
- el.resolution = { kind: 'submit', data: { selected: ['sum', 'charts'] } };
210
- </script>`,
211
- language: 'html',
212
- },
213
- },
214
- },
215
- };
216
-
217
- /** A malformed `data` (empty `tasks`) → the inline error state + an `error` event. */
218
- export const ErrorState: Story = {
219
- render: () => <TasksDemo def={{ tasks: [] } as unknown as TasksCardData} cardId="card-bad" />,
220
- parameters: {
221
- docs: {
222
- source: {
223
- code: `<kai-tasks></kai-tasks>
224
- <script type="module">
225
- import '@kitn.ai/ui/elements';
226
- const el = document.querySelector('kai-tasks');
227
- // No tasks → inline error state + an \`error\` event.
228
- el.data = { tasks: [] };
229
- el.addEventListener('kai-card', (e) => {
230
- if (e.detail.kind === 'error') console.warn('tasks error:', e.detail.message);
231
- });
232
- </script>`,
233
- language: 'html',
234
- },
235
- },
236
- },
237
- };
@@ -1,64 +0,0 @@
1
- import type { Meta, StoryObj } from 'storybook-solidjs-vite';
2
- import './register'; // side effect: registers the custom elements
3
- import { argTypesFor, specDescription } from '../stories/docs/element-controls';
4
-
5
- // The web components are custom DOM elements, so declare the tags for JSX.
6
- declare module 'solid-js' {
7
- // eslint-disable-next-line @typescript-eslint/no-namespace
8
- namespace JSX {
9
- interface IntrinsicElements {
10
- 'kai-text-shimmer': JSX.HTMLAttributes<HTMLElement> & {
11
- text?: string;
12
- duration?: number;
13
- spread?: number;
14
- };
15
- }
16
- }
17
- }
18
-
19
- const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
20
- <kai-text-shimmer text="Thinking…" duration="3" spread="20"></kai-text-shimmer>
21
-
22
- <script type="module">
23
- import '@kitn.ai/ui/elements'; // registers the custom elements
24
- </script>`;
25
-
26
- const meta = {
27
- title: 'Components/TextShimmer',
28
- tags: ['autodocs'],
29
- argTypes: argTypesFor('kai-text-shimmer'),
30
- parameters: {
31
- layout: 'fullscreen',
32
- docs: {
33
- description: specDescription('kai-text-shimmer', [
34
- '`<kai-text-shimmer>` is the framework-agnostic **web component** for animated shimmering text — a gradient sweep across a label, isolated in **Shadow DOM**.',
35
- '**When to use:** signalling a quiet, in-progress state ("Thinking…", "Generating…") inline. In SolidJS, use the `TextShimmer` primitive.',
36
- '**Placement:** inline within a status row, toolbar label, or above a streaming content area — it renders as an inline `span` so it flows naturally alongside other text or icons.',
37
- "**How to use:** register once with `import '@kitn.ai/ui/elements'`, set the `text` attribute, and tune `duration` (seconds) and `spread` (gradient width, 5–45).",
38
- 'See the **Code** tab for HTML usage.',
39
- ]),
40
- },
41
- },
42
- } satisfies Meta;
43
-
44
- export default meta;
45
- type Story = StoryObj;
46
-
47
- /** Default shimmer. */
48
- export const Default: Story = {
49
- render: () => (
50
- <div style={{ padding: '24px', 'font-size': '18px' }}>
51
- <kai-text-shimmer text="Thinking…" />
52
- </div>
53
- ),
54
- parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
55
- };
56
-
57
- /** Faster sweep with a wider gradient spread. */
58
- export const Tuned: Story = {
59
- render: () => (
60
- <div style={{ padding: '24px', 'font-size': '18px' }}>
61
- <kai-text-shimmer text="Generating response…" duration={2} spread={35} />
62
- </div>
63
- ),
64
- };
@@ -1,72 +0,0 @@
1
- import type { Meta, StoryObj } from 'storybook-solidjs-vite';
2
- import './register'; // side effect: registers the custom elements
3
- import { argTypesFor, specDescription } from '../stories/docs/element-controls';
4
-
5
- // The web components are custom DOM elements, so declare the tags for JSX.
6
- declare module 'solid-js' {
7
- // eslint-disable-next-line @typescript-eslint/no-namespace
8
- namespace JSX {
9
- interface IntrinsicElements {
10
- 'kai-thinking-bar': JSX.HTMLAttributes<HTMLElement> & {
11
- text?: string;
12
- stoppable?: boolean | string;
13
- 'stop-label'?: string;
14
- 'on:kai-stop'?: (e: CustomEvent) => void;
15
- };
16
- }
17
- }
18
- }
19
-
20
- const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
21
- <kai-thinking-bar text="Thinking" stoppable stop-label="Answer now"></kai-thinking-bar>
22
-
23
- <script type="module">
24
- import '@kitn.ai/ui/elements'; // registers the custom elements
25
-
26
- document.querySelector('kai-thinking-bar')
27
- .addEventListener('kai-stop', () => console.log('user asked to stop'));
28
- </script>`;
29
-
30
- const meta = {
31
- title: 'Components/ThinkingBar',
32
- tags: ['autodocs'],
33
- argTypes: argTypesFor('kai-thinking-bar'),
34
- parameters: {
35
- layout: 'fullscreen',
36
- docs: {
37
- description: specDescription('kai-thinking-bar', [
38
- '`<kai-thinking-bar>` is the framework-agnostic **web component** for an animated "thinking" indicator with an optional stop affordance — a pure leaf element isolated in **Shadow DOM**. (`<kai-chat>` does not surface this; compose it yourself.)',
39
- '**When to use:** showing that the assistant is reasoning, optionally letting the user interrupt with "Answer now". In SolidJS, use the `ThinkingBar` primitive.',
40
- "**How to use:** register once with `import '@kitn.ai/ui/elements'`, set the `text`/`stop-label` attributes, add the `stoppable` flag to show the stop button, and listen for the `kai-stop` **CustomEvent**.",
41
- 'See the **Code** tab for HTML usage.',
42
- ]),
43
- },
44
- },
45
- } satisfies Meta;
46
-
47
- export default meta;
48
- type Story = StoryObj;
49
-
50
- /** A plain thinking indicator. */
51
- export const Default: Story = {
52
- render: () => (
53
- <div style={{ padding: '24px' }}>
54
- <kai-thinking-bar text="Thinking" />
55
- </div>
56
- ),
57
- parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
58
- };
59
-
60
- /** Stoppable — shows an "Answer now" affordance that fires a `stop` event. */
61
- export const Stoppable: Story = {
62
- render: () => (
63
- <div style={{ padding: '24px' }}>
64
- <kai-thinking-bar
65
- text="Reasoning"
66
- stoppable
67
- stop-label="Answer now"
68
- on:kai-stop={() => console.log('stop')}
69
- />
70
- </div>
71
- ),
72
- };
@@ -1,89 +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 type { ToolPart } from '../components/tool';
5
- import { argTypesFor, specDescription } from '../stories/docs/element-controls';
6
-
7
- // The web components are custom DOM elements, so declare the tags for JSX.
8
- declare module 'solid-js' {
9
- // eslint-disable-next-line @typescript-eslint/no-namespace
10
- namespace JSX {
11
- interface IntrinsicElements {
12
- 'kai-tool': JSX.HTMLAttributes<HTMLElement>;
13
- }
14
- }
15
- }
16
-
17
- const completedTool: ToolPart = {
18
- type: 'database_query',
19
- state: 'output-available',
20
- input: { table: 'users', limit: 10 },
21
- output: { rows: 10, ms: 42 },
22
- };
23
-
24
- const runningTool: ToolPart = {
25
- type: 'search',
26
- state: 'input-available',
27
- input: { query: 'kitn docs' },
28
- };
29
-
30
- /** Render the actual `<kai-tool>` custom element with a `tool` property. */
31
- function ToolElement(props: { tool: ToolPart; open?: boolean }) {
32
- let el: (HTMLElement & { tool?: ToolPart; open?: boolean }) | undefined;
33
- onMount(() => {
34
- if (el) {
35
- el.tool = props.tool;
36
- if (props.open) el.open = true;
37
- }
38
- });
39
- return (
40
- <kai-tool ref={(e) => (el = e as HTMLElement)} style={{ display: 'block', padding: '16px', 'max-width': '720px' }} />
41
- );
42
- }
43
-
44
- const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
45
- <kai-tool id="tool" open></kai-tool>
46
-
47
- <script type="module">
48
- import '@kitn.ai/ui/elements'; // registers the custom elements
49
-
50
- const tool = document.getElementById('tool');
51
- tool.tool = {
52
- type: 'database_query',
53
- state: 'output-available',
54
- input: { table: 'users', limit: 10 },
55
- output: { rows: 10, ms: 42 },
56
- };
57
- </script>`;
58
-
59
- const meta = {
60
- title: 'Components/Tool',
61
- tags: ['autodocs'],
62
- argTypes: argTypesFor('kai-tool'),
63
- parameters: {
64
- layout: 'fullscreen',
65
- docs: {
66
- description: specDescription('kai-tool', [
67
- '`<kai-tool>` is the framework-agnostic **web component** for a single tool-call panel — a collapsible input/output inspector with a state badge — isolated in **Shadow DOM**.',
68
- '**When to use:** rendering an agent/tool-call trace in a non-Solid app. In SolidJS, use the `Tool` primitive directly.',
69
- '**Placement:** inline inside an assistant message row, one element per tool call, below the text content; renders as a block sized to its content.',
70
- "**How to use:** register once with `import '@kitn.ai/ui/elements'`, set the call via the `tool` **property** (`el.tool = {...}`), and add the `open` flag to start it expanded.",
71
- 'See the **Code** tab for HTML usage.',
72
- ]),
73
- },
74
- },
75
- } satisfies Meta;
76
-
77
- export default meta;
78
- type Story = StoryObj;
79
-
80
- /** A completed call with input and output, started expanded. */
81
- export const Completed: Story = {
82
- render: () => <ToolElement tool={completedTool} open />,
83
- parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
84
- };
85
-
86
- /** A call still awaiting output (collapsed). */
87
- export const Running: Story = {
88
- render: () => <ToolElement tool={runningTool} />,
89
- };
@@ -1,88 +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-voice-input': JSX.HTMLAttributes<HTMLElement> & {
12
- disabled?: boolean | string;
13
- };
14
- }
15
- }
16
- }
17
-
18
- /** Render `<kai-voice-input>` with a stub `transcribe` function-property. */
19
- function VoiceElement(props: { disabled?: boolean }) {
20
- let el: (HTMLElement & { transcribe?: (audio: Blob) => Promise<string> }) | undefined;
21
- onMount(() => {
22
- if (!el) return;
23
- // transcribe MUST be set as a JS property — a value-returning callback
24
- // can't be modelled as an attribute.
25
- el.transcribe = async () => {
26
- await new Promise((r) => setTimeout(r, 400));
27
- return 'transcribed text';
28
- };
29
- el.addEventListener('kai-transcription', (e) => {
30
- const ev = e as CustomEvent<{ text: string }>;
31
- console.log('kai-transcription', ev.detail.text);
32
- });
33
- });
34
- return (
35
- <kai-voice-input
36
- ref={(e) => (el = e as HTMLElement)}
37
- disabled={props.disabled ? true : undefined}
38
- style={{ display: 'inline-block', padding: '40px' }}
39
- />
40
- );
41
- }
42
-
43
- const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
44
- <kai-voice-input id="voice"></kai-voice-input>
45
-
46
- <script type="module">
47
- import '@kitn.ai/ui/elements'; // registers the custom elements
48
-
49
- const voice = document.getElementById('voice');
50
- // transcribe is a FUNCTION property — your async transcriber
51
- voice.transcribe = async (blob) => {
52
- const text = await myTranscriptionApi(blob);
53
- return text;
54
- };
55
- voice.addEventListener('kai-transcription', (e) => console.log(e.detail.text));
56
- </script>`;
57
-
58
- const meta = {
59
- title: 'Components/VoiceInput',
60
- tags: ['autodocs'],
61
- argTypes: argTypesFor('kai-voice-input'),
62
- parameters: {
63
- layout: 'fullscreen',
64
- docs: {
65
- description: specDescription('kai-voice-input', [
66
- '`<kai-voice-input>` is the framework-agnostic **web component** for a mic button that records and transcribes audio — isolated in **Shadow DOM**. It is the canonical **function-property** element.',
67
- '**When to use:** adding voice dictation to an input in a non-Solid app. In SolidJS, use the `VoiceInput` primitive.',
68
- '**Placement:** inline beside the prompt input field or as an icon button in the composer toolbar; renders as an inline-block sized to the mic button.',
69
- "**How to use:** register once with `import '@kitn.ai/ui/elements'`, then set the `transcribe` **function property** (`el.transcribe = async blob => '...'`) — a value-returning callback can't be modelled as an event. It also emits `kai-audio-captured` (raw blob) and `kai-transcription` (text) **CustomEvents**.",
70
- 'See the **Code** tab for HTML usage.',
71
- ]),
72
- },
73
- },
74
- } satisfies Meta;
75
-
76
- export default meta;
77
- type Story = StoryObj;
78
-
79
- /** A working mic button wired to a stub transcriber. */
80
- export const Default: Story = {
81
- render: () => <VoiceElement />,
82
- parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
83
- };
84
-
85
- /** A disabled mic button (non-interactive). */
86
- export const Disabled: Story = {
87
- render: () => <VoiceElement disabled />,
88
- };
@@ -1,47 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { createRoot, createSignal } from 'solid-js';
3
- import { createControllableSignal } from './controllable';
4
-
5
- describe('createControllableSignal', () => {
6
- it('uses the initial value when uncontrolled (controlled accessor is undefined)', () => {
7
- createRoot((dispose) => {
8
- const [value] = createControllableSignal(() => undefined, true);
9
- expect(value()).toBe(true);
10
- dispose();
11
- });
12
- });
13
-
14
- it('updates via the setter when uncontrolled', () => {
15
- createRoot((dispose) => {
16
- const [value, setValue] = createControllableSignal(() => undefined, false);
17
- setValue(true);
18
- expect(value()).toBe(true);
19
- dispose();
20
- });
21
- });
22
-
23
- it('reflects the controlled value and ignores the internal setter while controlled', () => {
24
- createRoot((dispose) => {
25
- const [controlled, setControlled] = createSignal<boolean | undefined>(false);
26
- const [value, setValue] = createControllableSignal(controlled, false);
27
- expect(value()).toBe(false);
28
- setValue(true); // masked while controlled
29
- expect(value()).toBe(false);
30
- setControlled(true); // the controlling value wins
31
- expect(value()).toBe(true);
32
- dispose();
33
- });
34
- });
35
-
36
- it('falls back to the internal value when control is released (becomes undefined)', () => {
37
- createRoot((dispose) => {
38
- const [controlled, setControlled] = createSignal<boolean | undefined>(true);
39
- const [value, setValue] = createControllableSignal(controlled, false);
40
- expect(value()).toBe(true);
41
- setValue(true); // sets internal (masked now)
42
- setControlled(undefined); // uncontrolled → internal shows
43
- expect(value()).toBe(true);
44
- dispose();
45
- });
46
- });
47
- });