@kitn.ai/ui 0.28.0 → 0.30.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 (615) hide show
  1. package/README.md +11 -7
  2. package/dist/{Icon-DObhsRtm.js → Icon-BzBET3E-.js} +1 -1
  3. package/dist/{action-icons-CcgNN2oT.js → action-icons-DaW2pU6m.js} +1 -1
  4. package/dist/agent-tooling/construct/public.d.ts +15 -0
  5. package/dist/agent-tooling/construct/schema.d.ts +111 -0
  6. package/dist/arrow-down-D783iMJj.js +1 -0
  7. package/dist/arrow-left-0VLM5kyg.js +1 -0
  8. package/dist/artifact-DGjzHYUT.js +1 -0
  9. package/dist/{attachments-Qr4kg-2b.js → attachments-YvXHlg88.js} +1 -1
  10. package/dist/{audio-visualizer-DToYdfSc.js → audio-visualizer-9lz5IHsL.js} +1 -1
  11. package/dist/{badge-CdEu_jn2.js → badge-Dh_vp8A5.js} +1 -1
  12. package/dist/{bell-DQAAOpDz.js → bell-CT7_WUwS.js} +1 -1
  13. package/dist/{button-DkuOnGLy.js → button-C_3te6fm.js} +1 -1
  14. package/dist/{card-renderer-Jx70m6_l.js → card-renderer-DZVaGH2e.js} +1 -1
  15. package/dist/check-CiEOVnEN.js +1 -0
  16. package/dist/{checkbox-D7iRB3nL.js → checkbox-Bu2T2e0U.js} +1 -1
  17. package/dist/{checkbox-group-B2_rpoPM.js → checkbox-group-BiryEXPQ.js} +1 -1
  18. package/dist/chevron-down-CSobuZRG.js +1 -0
  19. package/dist/chevron-right-DR9ZAP-2.js +1 -0
  20. package/dist/{choice-card-m0BYqqOK.js → choice-card-CM6IjkmL.js} +1 -1
  21. package/dist/circle-BC66EYF7.js +1 -0
  22. package/dist/circle-check-BqmahW0O.js +1 -0
  23. package/dist/{circle-x-BPG0iPst.js → circle-x-Bk-dA5Wf.js} +1 -1
  24. package/dist/{code-block-ClMLKb7C.js → code-block-B26t-Q7q.js} +1 -1
  25. package/dist/{collapsible-B4DlWicL.js → collapsible-Bhc636Cf.js} +1 -1
  26. package/dist/components/builder-composer-triggers.d.ts +62 -0
  27. package/dist/components/builder-layout.d.ts +54 -0
  28. package/dist/components/builder-message-actions.d.ts +72 -0
  29. package/dist/components/builder-panel.d.ts +189 -0
  30. package/dist/components/builder-preview.d.ts +11 -0
  31. package/dist/components/builder-shell-controls.d.ts +69 -0
  32. package/dist/components/builder-skeleton.d.ts +58 -0
  33. package/dist/components/builder-start.d.ts +75 -0
  34. package/dist/components/builder-workspace-variants.d.ts +23 -0
  35. package/dist/components/captions.d.ts +66 -0
  36. package/dist/{composer-sQ0HcvyG.js → composer-DMI85B6j.js} +1 -1
  37. package/dist/{confirm-card-rQWDQsnC.js → confirm-card-B0YIAwXp.js} +1 -1
  38. package/dist/construct-cli.es.js +3 -3
  39. package/dist/construct.d.ts +5 -0
  40. package/dist/construct.js +327 -0
  41. package/dist/{context-0kg4ZX1J.js → context-DWgfhqWp.js} +1 -1
  42. package/dist/controllable-BagRpyHv.js +1 -0
  43. package/dist/{conversation-item-BxwQLaFJ.js → conversation-item-BsOsVGmT.js} +1 -1
  44. package/dist/{conversation-list-BCfGN1JU.js → conversation-list-aX3Vtc7L.js} +1 -1
  45. package/dist/{copy-n9u9rqpi.js → copy-BmEwsNhJ.js} +1 -1
  46. package/dist/core-C8fzo39E.js +1 -12
  47. package/dist/{create-tween-uPkArjIG.js → create-tween-CNOAU3Fx.js} +1 -1
  48. package/dist/{create-tween-C-q-JCM-.js → create-tween-WfqiENls.js} +1 -1
  49. package/dist/{create-tween-CRrJXxBd.js → create-tween-wlFtW9Kh.js} +1 -1
  50. package/dist/{create-tween-DZ3RRDHD.js → create-tween-zt79ba32.js} +1 -1
  51. package/dist/{default-input-CaMrJkgH.js → default-input-DMV5Eaze.js} +1 -1
  52. package/dist/define-CI0y3eE4.js +1 -0
  53. package/dist/define.js +40 -40
  54. package/dist/define.server.js +45 -45
  55. package/dist/{disclosure-WUImBbDv.js → disclosure-NnACBxsC.js} +1 -1
  56. package/dist/{dropdown-wZVeJOMd.js → dropdown-DT7G0RGR.js} +1 -1
  57. package/dist/elements/agent-card.js +1 -1
  58. package/dist/elements/artifact.js +1 -1
  59. package/dist/elements/attachments.js +1 -1
  60. package/dist/elements/audio-visualizer.js +1 -1
  61. package/dist/elements/avatar.js +1 -1
  62. package/dist/elements/badge.js +1 -1
  63. package/dist/elements/button.js +1 -1
  64. package/dist/elements/card.js +1 -1
  65. package/dist/elements/cards.js +1 -1
  66. package/dist/elements/chain-of-thought.js +1 -1
  67. package/dist/elements/chat-scope-picker.js +1 -1
  68. package/dist/elements/chat-workspace.js +1 -1
  69. package/dist/elements/chat.js +1 -1
  70. package/dist/elements/checkbox-group.js +1 -1
  71. package/dist/elements/checkbox.js +1 -1
  72. package/dist/elements/checkpoint.js +1 -1
  73. package/dist/elements/choice.js +1 -1
  74. package/dist/elements/coachmark.js +1 -1
  75. package/dist/elements/code-block.js +1 -1
  76. package/dist/elements/command.js +1 -1
  77. package/dist/elements/compare.js +1 -1
  78. package/dist/elements/composer.js +1 -1
  79. package/dist/elements/confirm-card.js +1 -1
  80. package/dist/elements/context-meter.js +1 -1
  81. package/dist/elements/conversation-item.js +1 -1
  82. package/dist/elements/conversation-list.js +1 -1
  83. package/dist/elements/dialog.js +1 -1
  84. package/dist/elements/dock.js +1 -1
  85. package/dist/elements/dropdown.js +1 -1
  86. package/dist/elements/editable-label.js +1 -1
  87. package/dist/elements/embed.js +1 -1
  88. package/dist/elements/empty.js +1 -1
  89. package/dist/elements/feedback-bar.js +1 -1
  90. package/dist/elements/file-tree.js +1 -1
  91. package/dist/elements/file-upload.js +1 -1
  92. package/dist/elements/form.js +1 -1
  93. package/dist/elements/hover-card.js +1 -1
  94. package/dist/elements/icon.js +1 -1
  95. package/dist/elements/image.js +1 -1
  96. package/dist/elements/input.js +1 -1
  97. package/dist/elements/kbd.js +1 -1
  98. package/dist/elements/link-preview.js +1 -1
  99. package/dist/elements/loader.js +1 -1
  100. package/dist/elements/markdown.js +1 -1
  101. package/dist/elements/menu.js +1 -1
  102. package/dist/elements/message-skills.js +1 -1
  103. package/dist/elements/message.js +1 -1
  104. package/dist/elements/model-switcher.js +1 -1
  105. package/dist/elements/nav.js +1 -1
  106. package/dist/elements/notice.js +1 -1
  107. package/dist/elements/pane-grid.js +1 -1
  108. package/dist/elements/pane-group.js +1 -1
  109. package/dist/elements/pane.js +1 -1
  110. package/dist/elements/popover.js +1 -1
  111. package/dist/elements/progress-bar.js +1 -1
  112. package/dist/elements/prompt-dock.js +1 -1
  113. package/dist/elements/prompt-input.js +1 -1
  114. package/dist/elements/prompt-suggestions.js +1 -1
  115. package/dist/elements/radio-group.js +1 -1
  116. package/dist/elements/reasoning.js +1 -1
  117. package/dist/elements/remote.js +1 -1
  118. package/dist/elements/resizable.js +1 -1
  119. package/dist/elements/response-stream.js +1 -1
  120. package/dist/elements/screen.js +1 -1
  121. package/dist/elements/scroll-area.js +1 -1
  122. package/dist/elements/scroll-button.js +1 -1
  123. package/dist/elements/search.js +1 -1
  124. package/dist/elements/segmented.js +1 -1
  125. package/dist/elements/select.js +1 -1
  126. package/dist/elements/separator.js +1 -1
  127. package/dist/elements/setting-item.js +1 -1
  128. package/dist/elements/settings-group.js +1 -1
  129. package/dist/elements/skeleton.js +1 -1
  130. package/dist/elements/slider.js +1 -1
  131. package/dist/elements/source.js +1 -1
  132. package/dist/elements/status.js +1 -1
  133. package/dist/elements/switch.js +1 -1
  134. package/dist/elements/tabs.js +1 -1
  135. package/dist/elements/tasks.js +1 -1
  136. package/dist/elements/text-shimmer.js +1 -1
  137. package/dist/elements/thinking-bar.js +1 -1
  138. package/dist/elements/thread.js +1 -1
  139. package/dist/elements/toast.js +1 -1
  140. package/dist/elements/tool.js +1 -1
  141. package/dist/elements/tooltip.js +1 -1
  142. package/dist/elements/voice-input.js +1 -1
  143. package/dist/elements/voice-output.js +1 -1
  144. package/dist/{ellipsis-CbOpJnU3.js → ellipsis-6pJ7SxYT.js} +1 -1
  145. package/dist/{embed-CrfjkbUG.js → embed-BMje-nxj.js} +1 -1
  146. package/dist/engine-javascript-C1x7zo1_.js +1 -141
  147. package/dist/{external-link-ByXAwBBQ.js → external-link-Beh9DKeR.js} +1 -1
  148. package/dist/{file-text-DMib2qwt.js → file-text-D1GPfZ8Q.js} +1 -1
  149. package/dist/{file-tree-CJqM2aP7.js → file-tree-Dwj2lqg-.js} +1 -1
  150. package/dist/{folder-_BAb929C.js → folder-b6D8x1DY.js} +1 -1
  151. package/dist/{form-DSZgZQZk.js → form-DWgdxDXu.js} +1 -1
  152. package/dist/{hover-card-BQbul9eq.js → hover-card-CWRkqm40.js} +1 -1
  153. package/dist/{icon-CdcfRhYI.js → icon-CL0jdhsf.js} +1 -1
  154. package/dist/index.js +1741 -1725
  155. package/dist/index.server.js +1582 -1566
  156. package/dist/{info-DsFjGuI_.js → info-0cOUherQ.js} +1 -1
  157. package/dist/{input-DKbmkMos.js → input-BH6Ru91Q.js} +1 -1
  158. package/dist/kai.es.js +1 -1
  159. package/dist/{kbd-PvdGhX4s.js → kbd-DRAnVtNX.js} +1 -1
  160. package/dist/{link-zF8PzWfF.js → link-Dlr0vssB.js} +1 -1
  161. package/dist/{link-preview-DbM1866N.js → link-preview-DODgRyV9.js} +1 -1
  162. package/dist/loader-KvJB6NrT.js +1 -0
  163. package/dist/{markdown-LMvmAyBk.js → markdown-DX9tuJVj.js} +1 -1
  164. package/dist/mcp.es.js +9 -5
  165. package/dist/{message-BYZECyek.js → message-BqQ7Ot5q.js} +1 -1
  166. package/dist/{message-BSsgvHvf.js → message-DkaGfBd8.js} +1 -1
  167. package/dist/message-circle-BPpp5QKv.js +1 -0
  168. package/dist/message-square-BLbsd9BJ.js +1 -0
  169. package/dist/{minimize-2-BQRoBV1V.js → minimize-2-CyOHJwcN.js} +1 -1
  170. package/dist/{model-switcher-CMpCOYcB.js → model-switcher-0hrKDiK2.js} +1 -1
  171. package/dist/{overlay-Cb-MkyDa.js → overlay-DBMFXie6.js} +1 -1
  172. package/dist/{panel-right-i8warFxT.js → panel-right-t8SWJL6e.js} +1 -1
  173. package/dist/{paperclip-ByY3UVO6.js → paperclip-CdzuOjbU.js} +1 -1
  174. package/dist/play-BXy1u7rW.js +1 -0
  175. package/dist/primitives/use-auto-resize.d.ts +11 -0
  176. package/dist/{progress-bar-jVAHvMUf.js → progress-bar-CiBtxMWT.js} +1 -1
  177. package/dist/{prompt-suggestion-CD-qtNgC.js → prompt-suggestion-I_DHP21i.js} +1 -1
  178. package/dist/{radio-BsoBMhkF.js → radio-C_p3n39l.js} +1 -1
  179. package/dist/{reasoning-4kBPtlTx.js → reasoning-BDwy_tIe.js} +1 -1
  180. package/dist/register-impl-DvEnhIxx.js +424 -0
  181. package/dist/{resizable-uPmY9VY-.js → resizable-SYC-fStM.js} +1 -1
  182. package/dist/{rotate-ccw-B2xn93py.js → rotate-ccw-B1nwmwuY.js} +1 -1
  183. package/dist/{rotate-cw-CMVLoCyH.js → rotate-cw-CLAnBcm1.js} +1 -1
  184. package/dist/{scroll-area-BqLUo8ZZ.js → scroll-area-zRyXoLhI.js} +1 -1
  185. package/dist/{scroll-button-DslXiJyL.js → scroll-button-jzrbYCG9.js} +1 -1
  186. package/dist/{select-2cLRtPGT.js → select-DM-0nEe0.js} +1 -1
  187. package/dist/{separator-BWQtNJcM.js → separator-BToOOoOt.js} +1 -1
  188. package/dist/{settings-BBR63jLg.js → settings-PaGo_S4U.js} +1 -1
  189. package/dist/{settings-group-B2ciy-Iw.js → settings-group-BFXGIfXq.js} +1 -1
  190. package/dist/{skeleton-CkHI-HgC.js → skeleton-DYpmFnnm.js} +1 -1
  191. package/dist/{slider-DDR9U-i0.js → slider-ebutAmkQ.js} +1 -1
  192. package/dist/{solid-DruVOXnf.js → solid-15v_3WVL.js} +3563 -3412
  193. package/dist/{solid-BzCFdL25.js → solid-5P-otgdi.js} +4502 -4296
  194. package/dist/solid.d.ts +6 -0
  195. package/dist/solid.js +259 -254
  196. package/dist/solid.server.js +259 -254
  197. package/dist/{source-GEnFF528.js → source-c1gpRl9h.js} +1 -1
  198. package/dist/{star-CilHq8GP.js → star-pcV_3LqF.js} +1 -1
  199. package/dist/{store-Ciyk6eZG.js → store-CSgbFFCg.js} +1 -1
  200. package/dist/{switch-KkeQIbuH.js → switch-Bh2OdLV2.js} +1 -1
  201. package/dist/{tasks-card-BrN4bggJ.js → tasks-card-CbqQAn2S.js} +1 -1
  202. package/dist/text-shimmer-BSzgEnDH.js +1 -0
  203. package/dist/textarea-DrYNt_0z.js +1 -0
  204. package/dist/theme.tokens.css +22 -21
  205. package/dist/{thumbs-up-CsT9Wzb9.js → thumbs-up-BL3-NenK.js} +1 -1
  206. package/dist/{toast-store-tgK6MuMv.js → toast-store-DkOlYczt.js} +1 -1
  207. package/dist/{tool-DzUjIBT8.js → tool-CeIWUVUe.js} +1 -1
  208. package/dist/{tooltip-Bkkg_4t0.js → tooltip-GA-nmg06.js} +1 -1
  209. package/dist/{trash-2-jBKxjGGQ.js → trash-2-CT66QWlm.js} +1 -1
  210. package/dist/{triangle-alert-DlQ68ppf.js → triangle-alert-CeHLWxhD.js} +1 -1
  211. package/dist/ui/color-field.d.ts +48 -0
  212. package/dist/ui/textarea.d.ts +4 -0
  213. package/dist/ui/toggle-chip.d.ts +40 -0
  214. package/dist/{upload-TcAHXv9W.js → upload-9Csb0F0J.js} +1 -1
  215. package/dist/{use-card-resolution-DaZqAdWf.js → use-card-resolution-Zg0a08Z-.js} +1 -1
  216. package/dist/{variant-aurora-DbW_OWL2.js → variant-aurora-4VBQHIKV.js} +1 -1
  217. package/dist/{variant-aurora-CNmfHhcx.js → variant-aurora-DBeCAQNk.js} +2 -2
  218. package/dist/{variant-aurora-D6GsdTPA.js → variant-aurora-FzHVXHby.js} +2 -2
  219. package/dist/{variant-aurora-BhLuYxJR.js → variant-aurora-LE3fqxgw.js} +1 -1
  220. package/dist/{variant-custom-BvYHR62b.js → variant-custom-AFRGcOBS.js} +1 -1
  221. package/dist/{variant-custom-DV2x254s.js → variant-custom-BQkNuPpE.js} +2 -2
  222. package/dist/{variant-custom-BRvaNHSi.js → variant-custom-DI5R0rln.js} +1 -1
  223. package/dist/{variant-custom-DMTrEO5w.js → variant-custom-WWnrrRHS.js} +2 -2
  224. package/dist/{variant-wave-CyBueXj9.js → variant-wave-DUCbH5oI.js} +2 -2
  225. package/dist/{variant-wave-BNMGrDfj.js → variant-wave-DuQV7DhQ.js} +2 -2
  226. package/dist/{variant-wave-BpDd8t3Z.js → variant-wave-nSI2sfII.js} +1 -1
  227. package/dist/{variant-wave-sp-qwsdI.js → variant-wave-wTP5v_jU.js} +1 -1
  228. package/dist/x-eiO9V6J6.js +1 -0
  229. package/{src/elements/styles.css → kit-base.css} +27 -44
  230. package/package.json +32 -17
  231. package/solid.css +33 -0
  232. package/theme.css +39 -23
  233. package/bin/route.test.js +0 -58
  234. package/dist/arrow-down-CjRU3JgV.js +0 -1
  235. package/dist/arrow-left-Bnpb1UEW.js +0 -1
  236. package/dist/artifact-Bwt7OgcR.js +0 -1
  237. package/dist/check-njkVdZu2.js +0 -1
  238. package/dist/chevron-down-B72s6PXR.js +0 -1
  239. package/dist/chevron-right-BatuHzUm.js +0 -1
  240. package/dist/circle-check-B62pODB3.js +0 -1
  241. package/dist/circle-zx0ByzY9.js +0 -1
  242. package/dist/controllable-CnGpMF6r.js +0 -1
  243. package/dist/define-By-uL588.js +0 -1
  244. package/dist/loader-BM4CEz4G.js +0 -1
  245. package/dist/message-circle-DruwObfX.js +0 -1
  246. package/dist/message-square-BG6q6mlm.js +0 -1
  247. package/dist/play-BvKKq3fX.js +0 -1
  248. package/dist/register-impl-B1hLkrI8.js +0 -424
  249. package/dist/text-shimmer-Dcj1MHuq.js +0 -1
  250. package/dist/textarea-Dpvbngbg.js +0 -1
  251. package/dist/x-Z5UntkIJ.js +0 -1
  252. package/src/agent-tooling/README.md +0 -192
  253. package/src/agent-tooling/archetypes.ts +0 -205
  254. package/src/agent-tooling/catalog/README.md +0 -676
  255. package/src/agent-tooling/catalog/catalog-types.ts +0 -231
  256. package/src/agent-tooling/catalog/fabrications.ts +0 -96
  257. package/src/agent-tooling/catalog/invariants.ts +0 -284
  258. package/src/agent-tooling/catalog/labs-titles.ts +0 -114
  259. package/src/agent-tooling/catalog/scenarios.ts +0 -87
  260. package/src/agent-tooling/catalog/surfaces.ts +0 -347
  261. package/src/agent-tooling/construct/cli-entry.ts +0 -8
  262. package/src/agent-tooling/construct/cli.ts +0 -147
  263. package/src/agent-tooling/construct/codegen.ts +0 -1635
  264. package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
  265. package/src/agent-tooling/construct/dev.ts +0 -148
  266. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
  267. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
  268. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
  269. package/src/agent-tooling/construct/schema.ts +0 -452
  270. package/src/agent-tooling/integrations/anthropic.ts +0 -442
  271. package/src/agent-tooling/integrations/cloudflare.ts +0 -218
  272. package/src/agent-tooling/integrations/langgraph.ts +0 -133
  273. package/src/agent-tooling/integrations/mastra.ts +0 -182
  274. package/src/agent-tooling/integrations/mock.ts +0 -148
  275. package/src/agent-tooling/integrations/ollama.ts +0 -97
  276. package/src/agent-tooling/integrations/openai.ts +0 -95
  277. package/src/agent-tooling/integrations/openrouter.ts +0 -82
  278. package/src/agent-tooling/integrations/pi.ts +0 -176
  279. package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
  280. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
  281. package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
  282. package/src/agent-tooling/mcp/manifest.ts +0 -422
  283. package/src/agent-tooling/mcp/server.ts +0 -116
  284. package/src/agent-tooling/mcp/stdio.ts +0 -18
  285. package/src/agent-tooling/mcp/tools/construct.ts +0 -130
  286. package/src/agent-tooling/mcp/tools/debug.ts +0 -621
  287. package/src/agent-tooling/mcp/tools/reference.ts +0 -980
  288. package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
  289. package/src/agent-tooling/mcp/tools/theme.ts +0 -456
  290. package/src/agent-tooling/mcp/tools/types.ts +0 -14
  291. package/src/agent-tooling/mcp/validate-args.ts +0 -141
  292. package/src/agent-tooling/recipes/composed-thread.ts +0 -714
  293. package/src/agent-tooling/recipes/index.ts +0 -22
  294. package/src/agent-tooling/recipes/types.ts +0 -32
  295. package/src/agent-tooling/registry.ts +0 -132
  296. package/src/agent-tooling/route-emit.ts +0 -305
  297. package/src/agent-tooling/types.ts +0 -390
  298. package/src/components/artifact-card.tsx +0 -120
  299. package/src/components/artifact.tsx +0 -914
  300. package/src/components/attachment-types.ts +0 -66
  301. package/src/components/attachments.tsx +0 -536
  302. package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
  303. package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
  304. package/src/components/audio-visualizer/fit-scale.ts +0 -112
  305. package/src/components/audio-visualizer/index.tsx +0 -528
  306. package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
  307. package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
  308. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
  309. package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
  310. package/src/components/audio-visualizer/sizes.ts +0 -54
  311. package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
  312. package/src/components/audio-visualizer/variant-bar.tsx +0 -175
  313. package/src/components/audio-visualizer/variant-custom.tsx +0 -344
  314. package/src/components/audio-visualizer/variant-grid.tsx +0 -175
  315. package/src/components/audio-visualizer/variant-radial.tsx +0 -163
  316. package/src/components/audio-visualizer/variant-wave.tsx +0 -130
  317. package/src/components/audio-visualizer/wave.glsl.ts +0 -130
  318. package/src/components/card-fallback.tsx +0 -60
  319. package/src/components/card-renderer.tsx +0 -220
  320. package/src/components/card.tsx +0 -212
  321. package/src/components/chain-of-thought.tsx +0 -348
  322. package/src/components/chat-container.tsx +0 -89
  323. package/src/components/chat-scope-picker.tsx +0 -57
  324. package/src/components/chat-thread.tsx +0 -1014
  325. package/src/components/checkpoint.tsx +0 -88
  326. package/src/components/choice-card.tsx +0 -743
  327. package/src/components/coachmark.tsx +0 -249
  328. package/src/components/code-block.tsx +0 -181
  329. package/src/components/composer-dom.ts +0 -159
  330. package/src/components/composer-highlight.ts +0 -242
  331. package/src/components/composer-history.ts +0 -82
  332. package/src/components/composer.tsx +0 -1075
  333. package/src/components/confirm-card.tsx +0 -402
  334. package/src/components/context.tsx +0 -377
  335. package/src/components/conversation-item.tsx +0 -241
  336. package/src/components/conversation-list.tsx +0 -429
  337. package/src/components/conversation-panel.tsx +0 -118
  338. package/src/components/dismissed-stub.tsx +0 -80
  339. package/src/components/embed.tsx +0 -200
  340. package/src/components/empty.tsx +0 -177
  341. package/src/components/feedback-bar.tsx +0 -166
  342. package/src/components/file-tree.tsx +0 -530
  343. package/src/components/file-upload.tsx +0 -167
  344. package/src/components/form-widgets.tsx +0 -525
  345. package/src/components/form.tsx +0 -1296
  346. package/src/components/home-panel.tsx +0 -159
  347. package/src/components/image.tsx +0 -65
  348. package/src/components/link-preview.tsx +0 -195
  349. package/src/components/loader.tsx +0 -367
  350. package/src/components/markdown.tsx +0 -162
  351. package/src/components/message-skills.tsx +0 -40
  352. package/src/components/message.tsx +0 -765
  353. package/src/components/model-switcher.tsx +0 -132
  354. package/src/components/prompt-input.tsx +0 -188
  355. package/src/components/prompt-suggestion.tsx +0 -150
  356. package/src/components/reasoning.tsx +0 -293
  357. package/src/components/response-compare-types.ts +0 -152
  358. package/src/components/response-compare.tsx +0 -455
  359. package/src/components/response-stream.tsx +0 -109
  360. package/src/components/screen.tsx +0 -181
  361. package/src/components/scroll-button.tsx +0 -93
  362. package/src/components/source.tsx +0 -192
  363. package/src/components/tasks-card.tsx +0 -801
  364. package/src/components/text-shimmer.tsx +0 -37
  365. package/src/components/thinking-bar.tsx +0 -50
  366. package/src/components/thread.tsx +0 -228
  367. package/src/components/toast.tsx +0 -503
  368. package/src/components/tool-classify.ts +0 -26
  369. package/src/components/tool-types.ts +0 -49
  370. package/src/components/tool.tsx +0 -190
  371. package/src/components/use-card-resolution.ts +0 -44
  372. package/src/components/voice-input.tsx +0 -222
  373. package/src/components/voice-output.tsx +0 -242
  374. package/src/components/widget-tab-bar.tsx +0 -73
  375. package/src/components/workspace-shell.tsx +0 -285
  376. package/src/diagnostics/hook.ts +0 -352
  377. package/src/diagnostics/index.ts +0 -82
  378. package/src/diagnostics/report-request.ts +0 -296
  379. package/src/elements/agent-card.tsx +0 -67
  380. package/src/elements/artifact.tsx +0 -194
  381. package/src/elements/attachments.tsx +0 -140
  382. package/src/elements/audio-visualizer.tsx +0 -227
  383. package/src/elements/autoloader.ts +0 -89
  384. package/src/elements/avatar.tsx +0 -33
  385. package/src/elements/badge.tsx +0 -32
  386. package/src/elements/button.tsx +0 -149
  387. package/src/elements/card.tsx +0 -133
  388. package/src/elements/cards.tsx +0 -266
  389. package/src/elements/chain-of-thought.tsx +0 -141
  390. package/src/elements/chat-scope-picker.tsx +0 -65
  391. package/src/elements/chat-types.ts +0 -102
  392. package/src/elements/chat-workspace.tsx +0 -188
  393. package/src/elements/chat.tsx +0 -304
  394. package/src/elements/checkbox-group.tsx +0 -164
  395. package/src/elements/checkbox.tsx +0 -134
  396. package/src/elements/checkpoint.tsx +0 -47
  397. package/src/elements/choice.tsx +0 -100
  398. package/src/elements/coachmark.tsx +0 -90
  399. package/src/elements/code-block.tsx +0 -60
  400. package/src/elements/command.tsx +0 -197
  401. package/src/elements/compare.tsx +0 -111
  402. package/src/elements/compiled.css +0 -2
  403. package/src/elements/composer.tsx +0 -162
  404. package/src/elements/confirm-card.tsx +0 -76
  405. package/src/elements/context-meter.tsx +0 -107
  406. package/src/elements/conversation-item.tsx +0 -120
  407. package/src/elements/conversation-list.tsx +0 -203
  408. package/src/elements/css.ts +0 -5
  409. package/src/elements/default-input.tsx +0 -392
  410. package/src/elements/define-entry.ts +0 -12
  411. package/src/elements/define.tsx +0 -563
  412. package/src/elements/diagnostic-events.ts +0 -114
  413. package/src/elements/dialog.tsx +0 -145
  414. package/src/elements/disclosure.ts +0 -95
  415. package/src/elements/dock.tsx +0 -215
  416. package/src/elements/dropdown.tsx +0 -123
  417. package/src/elements/editable-label.tsx +0 -140
  418. package/src/elements/element-data-types.ts +0 -152
  419. package/src/elements/element-diagnostics.ts +0 -392
  420. package/src/elements/element-manifest.json +0 -354
  421. package/src/elements/element-nonscalar.json +0 -187
  422. package/src/elements/element-types.d.ts +0 -4353
  423. package/src/elements/embed.tsx +0 -35
  424. package/src/elements/empty.tsx +0 -29
  425. package/src/elements/feedback-bar.tsx +0 -66
  426. package/src/elements/file-tree.tsx +0 -62
  427. package/src/elements/file-upload.tsx +0 -44
  428. package/src/elements/form.tsx +0 -94
  429. package/src/elements/hover-card.tsx +0 -80
  430. package/src/elements/icon.tsx +0 -41
  431. package/src/elements/image.tsx +0 -32
  432. package/src/elements/input.tsx +0 -492
  433. package/src/elements/kbd.tsx +0 -45
  434. package/src/elements/link-preview.tsx +0 -34
  435. package/src/elements/loader.tsx +0 -25
  436. package/src/elements/markdown.tsx +0 -38
  437. package/src/elements/menu.tsx +0 -241
  438. package/src/elements/message-skills.tsx +0 -83
  439. package/src/elements/message.tsx +0 -361
  440. package/src/elements/model-switcher.tsx +0 -121
  441. package/src/elements/nav.tsx +0 -87
  442. package/src/elements/notice.tsx +0 -53
  443. package/src/elements/pane-grid.tsx +0 -111
  444. package/src/elements/pane-group.tsx +0 -119
  445. package/src/elements/pane.tsx +0 -129
  446. package/src/elements/popover.tsx +0 -81
  447. package/src/elements/progress-bar.tsx +0 -39
  448. package/src/elements/prompt-dock.tsx +0 -82
  449. package/src/elements/prompt-input.tsx +0 -240
  450. package/src/elements/prompt-suggestions.tsx +0 -113
  451. package/src/elements/radio-group.tsx +0 -129
  452. package/src/elements/reasoning.tsx +0 -71
  453. package/src/elements/register-impl.ts +0 -148
  454. package/src/elements/register.ts +0 -76
  455. package/src/elements/remote.tsx +0 -225
  456. package/src/elements/resizable.globals.d.ts +0 -36
  457. package/src/elements/resizable.tsx +0 -704
  458. package/src/elements/response-stream.tsx +0 -40
  459. package/src/elements/screen.tsx +0 -90
  460. package/src/elements/scroll-area.tsx +0 -33
  461. package/src/elements/scroll-button.tsx +0 -179
  462. package/src/elements/search.tsx +0 -185
  463. package/src/elements/segmented.tsx +0 -129
  464. package/src/elements/select.tsx +0 -165
  465. package/src/elements/separator.tsx +0 -36
  466. package/src/elements/setting-item.tsx +0 -50
  467. package/src/elements/settings-group.tsx +0 -37
  468. package/src/elements/skeleton.tsx +0 -45
  469. package/src/elements/slider.tsx +0 -171
  470. package/src/elements/slot-text.ts +0 -73
  471. package/src/elements/slots.ts +0 -787
  472. package/src/elements/source.tsx +0 -126
  473. package/src/elements/status.tsx +0 -42
  474. package/src/elements/switch.tsx +0 -118
  475. package/src/elements/tabs.tsx +0 -95
  476. package/src/elements/tasks.tsx +0 -103
  477. package/src/elements/text-shimmer.tsx +0 -28
  478. package/src/elements/thinking-bar.tsx +0 -43
  479. package/src/elements/thread.tsx +0 -139
  480. package/src/elements/toast.tsx +0 -106
  481. package/src/elements/tool.tsx +0 -78
  482. package/src/elements/tooltip.tsx +0 -85
  483. package/src/elements/validate-messages.ts +0 -76
  484. package/src/elements/voice-input.tsx +0 -100
  485. package/src/elements/voice-output.tsx +0 -82
  486. package/src/index.ts +0 -430
  487. package/src/primitives/audio-bands.ts +0 -174
  488. package/src/primitives/card-component-types.ts +0 -63
  489. package/src/primitives/card-contract.ts +0 -80
  490. package/src/primitives/card-data-types.ts +0 -361
  491. package/src/primitives/card-host.tsx +0 -37
  492. package/src/primitives/card-recovery.ts +0 -160
  493. package/src/primitives/card-registry.tsx +0 -78
  494. package/src/primitives/card-resolution.ts +0 -36
  495. package/src/primitives/card-routing.ts +0 -85
  496. package/src/primitives/card-schemas/artifact.schema.json +0 -92
  497. package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
  498. package/src/primitives/card-schemas/card-event.schema.json +0 -12
  499. package/src/primitives/card-schemas/choice.schema.json +0 -75
  500. package/src/primitives/card-schemas/confirm.schema.json +0 -65
  501. package/src/primitives/card-schemas/embed.schema.json +0 -63
  502. package/src/primitives/card-schemas/form.result.schema.json +0 -7
  503. package/src/primitives/card-schemas/form.schema.json +0 -53
  504. package/src/primitives/card-schemas/link.schema.json +0 -54
  505. package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
  506. package/src/primitives/card-schemas/tasks.schema.json +0 -83
  507. package/src/primitives/card-tags.ts +0 -61
  508. package/src/primitives/card-validate-cards.ts +0 -255
  509. package/src/primitives/card-validate-schemas.ts +0 -58
  510. package/src/primitives/card-validate.ts +0 -131
  511. package/src/primitives/chat-config.tsx +0 -103
  512. package/src/primitives/composer-model.ts +0 -49
  513. package/src/primitives/composer-triggers.ts +0 -35
  514. package/src/primitives/controllable.ts +0 -21
  515. package/src/primitives/conversation-store.ts +0 -248
  516. package/src/primitives/create-kai-chat.ts +0 -66
  517. package/src/primitives/create-tween.ts +0 -266
  518. package/src/primitives/embed-providers.ts +0 -254
  519. package/src/primitives/field-mask.ts +0 -256
  520. package/src/primitives/field-semantics.ts +0 -115
  521. package/src/primitives/highlighter.ts +0 -157
  522. package/src/primitives/input-mask.ts +0 -853
  523. package/src/primitives/link-preview.ts +0 -87
  524. package/src/primitives/message-feedback.ts +0 -124
  525. package/src/primitives/pdf-preview.ts +0 -121
  526. package/src/primitives/toast-store.ts +0 -338
  527. package/src/primitives/url-scheme-policy.ts +0 -70
  528. package/src/primitives/use-audio-analysis.ts +0 -340
  529. package/src/primitives/use-auto-resize.ts +0 -31
  530. package/src/primitives/use-resize-observer.ts +0 -45
  531. package/src/primitives/use-sequencer.ts +0 -72
  532. package/src/primitives/use-speech-recognition.ts +0 -146
  533. package/src/primitives/use-stick-to-bottom.ts +0 -75
  534. package/src/primitives/use-text-stream.ts +0 -143
  535. package/src/primitives/use-voice-recorder.ts +0 -62
  536. package/src/primitives/visualizer-sequences.ts +0 -350
  537. package/src/remote/host-embed.ts +0 -345
  538. package/src/remote/index.ts +0 -2
  539. package/src/remote/origin.ts +0 -30
  540. package/src/remote/provider-runtime.ts +0 -262
  541. package/src/remote/provider.ts +0 -2
  542. package/src/remote/validate.ts +0 -22
  543. package/src/remote/version.ts +0 -12
  544. package/src/remote/wire.ts +0 -48
  545. package/src/schemas/from-tool-call.ts +0 -151
  546. package/src/schemas/index.ts +0 -341
  547. package/src/schemas/provider-subsets.ts +0 -538
  548. package/src/schemas/registry.ts +0 -355
  549. package/src/schemas/tool-defs.ts +0 -793
  550. package/src/solid.ts +0 -173
  551. package/src/state/index.ts +0 -44
  552. package/src/state/messages.ts +0 -53
  553. package/src/state/mock.ts +0 -297
  554. package/src/state/parts.ts +0 -295
  555. package/src/state/persistence.ts +0 -180
  556. package/src/state/stream.ts +0 -246
  557. package/src/state/suggestions.ts +0 -9
  558. package/src/state/threads.ts +0 -142
  559. package/src/test-utils/fake-clock.ts +0 -88
  560. package/src/types.ts +0 -95
  561. package/src/ui/action-icons.ts +0 -53
  562. package/src/ui/agent-card.tsx +0 -218
  563. package/src/ui/avatar.tsx +0 -23
  564. package/src/ui/badge.tsx +0 -21
  565. package/src/ui/button.tsx +0 -49
  566. package/src/ui/card.tsx +0 -245
  567. package/src/ui/checkbox-group.tsx +0 -153
  568. package/src/ui/checkbox.tsx +0 -63
  569. package/src/ui/collapsible.tsx +0 -163
  570. package/src/ui/command.tsx +0 -103
  571. package/src/ui/dialog.tsx +0 -223
  572. package/src/ui/dock.tsx +0 -630
  573. package/src/ui/dropdown.tsx +0 -636
  574. package/src/ui/editable-label.tsx +0 -112
  575. package/src/ui/hover-card.tsx +0 -345
  576. package/src/ui/icon.tsx +0 -167
  577. package/src/ui/input.tsx +0 -391
  578. package/src/ui/kbd.tsx +0 -118
  579. package/src/ui/nav.tsx +0 -282
  580. package/src/ui/notice.tsx +0 -84
  581. package/src/ui/overlay.tsx +0 -277
  582. package/src/ui/pane-grid.tsx +0 -117
  583. package/src/ui/pane-group.tsx +0 -291
  584. package/src/ui/pane.tsx +0 -193
  585. package/src/ui/popover.tsx +0 -106
  586. package/src/ui/progress-bar.tsx +0 -83
  587. package/src/ui/prompt-dock.tsx +0 -145
  588. package/src/ui/radio.tsx +0 -150
  589. package/src/ui/resizable.tsx +0 -693
  590. package/src/ui/scroll-area.tsx +0 -26
  591. package/src/ui/segmented.tsx +0 -109
  592. package/src/ui/select.tsx +0 -168
  593. package/src/ui/separator.tsx +0 -10
  594. package/src/ui/settings-group.tsx +0 -67
  595. package/src/ui/skeleton.tsx +0 -73
  596. package/src/ui/slider.tsx +0 -178
  597. package/src/ui/status.tsx +0 -48
  598. package/src/ui/switch.tsx +0 -119
  599. package/src/ui/tabs.tsx +0 -168
  600. package/src/ui/textarea.tsx +0 -21
  601. package/src/ui/tooltip.tsx +0 -118
  602. package/src/utils/cn.ts +0 -30
  603. package/src/wire/chunk.ts +0 -248
  604. package/src/wire/consume.ts +0 -599
  605. package/src/wire/diagnostics.ts +0 -727
  606. package/src/wire/encode-probe.ts +0 -214
  607. package/src/wire/encode.ts +0 -947
  608. package/src/wire/files.ts +0 -342
  609. package/src/wire/formats/anthropic.ts +0 -274
  610. package/src/wire/formats/openai.ts +0 -228
  611. package/src/wire/index.ts +0 -95
  612. package/src/wire/media-types.ts +0 -344
  613. package/src/wire/read.ts +0 -396
  614. package/src/wire/sink-helpers.ts +0 -50
  615. package/src/wire/sse.ts +0 -153
@@ -1,801 +0,0 @@
1
- import {
2
- type JSX,
3
- For,
4
- Show,
5
- splitProps,
6
- mergeProps,
7
- createSignal,
8
- createMemo,
9
- createEffect,
10
- on,
11
- onMount,
12
- ErrorBoundary,
13
- createUniqueId,
14
- } from 'solid-js';
15
- import { cn } from '../utils/cn';
16
- import { Button } from '../ui/button';
17
- import { Checkbox } from '../ui/checkbox';
18
- import { ProgressBar } from '../ui/progress-bar';
19
- import { Card } from './card';
20
- import { DismissedStub } from './dismissed-stub';
21
- import type { CardEnvelope, CardEvent, CardHost, CardResolution } from '../primitives/card-contract';
22
- import { useCardResolution } from './use-card-resolution';
23
- import { emitCardEvent } from '../primitives/card-routing';
24
- import { useCardHost } from '../primitives/card-host';
25
- import { Check, Circle, CircleCheck } from 'lucide-solid';
26
-
27
- // ─────────────────────────────────────────────────────────────────────────────
28
- // Types (tasks.schema.json) — AUTHORED IN ../primitives/card-data-types.ts.
29
- // See the note in confirm-card.tsx, or that file's header, for why they left a
30
- // `.tsx` and why they are `type` aliases. Re-exported here unchanged.
31
- // ─────────────────────────────────────────────────────────────────────────────
32
-
33
- import type { TasksCardData, TasksCardResult, TasksTask } from '../primitives/card-data-types';
34
-
35
- export type {
36
- TasksCardData,
37
- TasksCardEnvelope,
38
- TasksCardResult,
39
- TasksTask,
40
- } from '../primitives/card-data-types';
41
-
42
- export const TASKS_CARD_TYPE = 'tasks' as const;
43
-
44
- // ─────────────────────────────────────────────────────────────────────────────
45
- // Pure helpers (unit-tested in isolation).
46
- // ─────────────────────────────────────────────────────────────────────────────
47
-
48
- /** De-dupe tasks by id (first wins). Returns the usable list + an optional error. */
49
- export function normalizeTasks(tasks: unknown): { tasks: TasksTask[]; error?: string } {
50
- if (!Array.isArray(tasks) || tasks.length === 0) {
51
- return { tasks: [], error: "This card couldn't be displayed." };
52
- }
53
- const seen = new Set<string>();
54
- const out: TasksTask[] = [];
55
- for (const t of tasks) {
56
- if (!t || typeof t !== 'object') continue;
57
- const task = t as Partial<TasksTask>;
58
- if (typeof task.id !== 'string' || task.id.length === 0) continue;
59
- if (typeof task.label !== 'string' || task.label.length === 0) continue;
60
- if (seen.has(task.id)) {
61
- // eslint-disable-next-line no-console
62
- console.warn(`[kai-tasks] duplicate task id "${task.id}" ignored`);
63
- continue;
64
- }
65
- seen.add(task.id);
66
- out.push({
67
- id: task.id,
68
- label: task.label,
69
- description: typeof task.description === 'string' ? task.description : undefined,
70
- checked: task.checked === true,
71
- disabled: task.disabled === true,
72
- });
73
- }
74
- if (out.length === 0) return { tasks: [], error: "This card couldn't be displayed." };
75
- return { tasks: out };
76
- }
77
-
78
- /** The ids of the initially-checked tasks (in input order). */
79
- export function initialSelected(tasks: TasksTask[]): string[] {
80
- return tasks.filter((t) => t.checked).map((t) => t.id);
81
- }
82
-
83
- /** The selected ids in input order (selection set ∩ tasks, preserving task order). */
84
- export function selectedInOrder(tasks: TasksTask[], selected: Set<string>): string[] {
85
- return tasks.filter((t) => selected.has(t.id)).map((t) => t.id);
86
- }
87
-
88
- /** The toggleable (non-disabled) task ids. */
89
- export function toggleableIds(tasks: TasksTask[]): string[] {
90
- return tasks.filter((t) => !t.disabled).map((t) => t.id);
91
- }
92
-
93
- export type SelectAllState = 'checked' | 'unchecked' | 'indeterminate';
94
-
95
- /** Select-all tri-state over the toggleable rows. */
96
- export function selectAllState(tasks: TasksTask[], selected: Set<string>): SelectAllState {
97
- const ids = toggleableIds(tasks);
98
- if (ids.length === 0) return 'unchecked';
99
- const n = ids.filter((id) => selected.has(id)).length;
100
- if (n === 0) return 'unchecked';
101
- if (n === ids.length) return 'checked';
102
- return 'indeterminate';
103
- }
104
-
105
- /** Whether select-all should be shown: requested AND not blocked by `max` (since
106
- * "all" would violate max). */
107
- export function showSelectAll(data: TasksCardData, tasks: TasksTask[]): boolean {
108
- if (data.selectAll !== true) return false;
109
- const count = toggleableIds(tasks).length;
110
- if (data.max !== undefined && count > data.max) return false;
111
- return true;
112
- }
113
-
114
- /** Whether the card is in the onboarding-checklist `progress` look (no confirm). */
115
- export function isProgressMode(data: TasksCardData): boolean {
116
- return data.mode === 'progress';
117
- }
118
-
119
- /** The header progress count (`done` checked / `total` rows) for `progress` mode. */
120
- export function progressCount(tasks: TasksTask[], selected: Set<string>): { done: number; total: number } {
121
- return { done: tasks.filter((t) => selected.has(t.id)).length, total: tasks.length };
122
- }
123
-
124
- /** Whether confirm is enabled for the current selection count. */
125
- export function canConfirm(data: TasksCardData, count: number): boolean {
126
- const min = data.min ?? (data.allowEmpty ? 0 : 1);
127
- if (count < min) return false;
128
- if (data.max !== undefined && count > data.max) return false;
129
- return true;
130
- }
131
-
132
- /** Whether an unchecked row is blocked because `max` is reached. */
133
- export function isMaxReached(data: TasksCardData, count: number): boolean {
134
- return data.max !== undefined && count >= data.max;
135
- }
136
-
137
- /** The disabled-reason text for confirm (for aria-describedby), or undefined. */
138
- export function confirmReason(data: TasksCardData, count: number): string | undefined {
139
- if (canConfirm(data, count)) return undefined;
140
- const min = data.min ?? (data.allowEmpty ? 0 : 1);
141
- if (count < min) return `Select at least ${min}.`;
142
- if (data.max !== undefined && count > data.max) return `Select at most ${data.max}.`;
143
- return undefined;
144
- }
145
-
146
- // ─────────────────────────────────────────────────────────────────────────────
147
- // The <TasksCard> component.
148
- // ─────────────────────────────────────────────────────────────────────────────
149
-
150
- /** Imperative handle exposed via `controllerRef` — surfaces the tasks card's latent
151
- * selection model (set the checked ids, toggle one, confirm, focus the group,
152
- * dismiss/reopen) so the `<kai-tasks>` facade can forward them as instance methods. */
153
- export interface TasksCardController {
154
- /** Set the checked ids (local-only, no emit), respecting disabled/max. No arg = select all toggleable rows. */
155
- select(taskIds?: string[]): void;
156
- /** Toggle one task by id, honoring the max gate. */
157
- toggle(taskId: string, checked?: boolean): void;
158
- /** Confirm the current selection (only when allowed) — emits `submit` + resolves. */
159
- send(): void;
160
- /** Focus the task group (select-all checkbox if shown, else the first row). */
161
- focus(options?: FocusOptions): void;
162
- /** Trigger the dismiss path (emit `dismiss` + collapse to the re-openable stub). */
163
- dismiss(): void;
164
- /** Re-open a dismissed card from its stub (emit `reopen`). */
165
- reopen(): void;
166
- }
167
-
168
- export interface TasksCardProps {
169
- /** The tasks definition (CardEnvelope.data). */
170
- data?: TasksCardData;
171
- /** The card id used to correlate every emitted CardEvent. */
172
- cardId?: string;
173
- /** The envelope title rendered in the card chrome. */
174
- heading?: string;
175
- /** Optional explicit CardHost (otherwise read from a CardProvider, otherwise the
176
- * bubbling `kai-card` CustomEvent off `hostElement`). */
177
- host?: CardHost;
178
- /** The custom-element host node, for the bubbling `kai-card` fallback emit. */
179
- hostElement?: HTMLElement;
180
- class?: string;
181
- /** When set, render the chromed read-only summary instead of the interactive controls. */
182
- resolution?: CardResolution;
183
- /** Controlled selection (task ids) — when set, this wins over internal state. */
184
- value?: string[];
185
- /** Uncontrolled initial selection (task ids), overlaying per-task `checked`. */
186
- defaultValue?: string[];
187
- /** Freeze the whole list + Confirm. */
188
- disabled?: boolean;
189
- /** Display-only: rows can't be toggled and show the default cursor (no pointer,
190
- * no hover background, no focus ring). Keeps the visual content as-is — this only
191
- * drops the interactive affordances + a11y exposure. */
192
- readonly?: boolean;
193
- /** Fires on every selection change with the selected ids (distinct from submit). */
194
- onValueChange?: (payload: { value: string[] }) => void;
195
- /** Receive the imperative controller once mounted. */
196
- controllerRef?: (controller: TasksCardController) => void;
197
- }
198
-
199
- const DEFAULT_DATA: TasksCardData = { tasks: [] };
200
-
201
- /**
202
- * `TasksCard` — a selectable task/plan list (checkbox rows + optional select-all
203
- * + a confirm button) inside `Card` chrome. Row toggling and select-all are local
204
- * UI state; only the final confirm emits the Card contract's `submit` verb
205
- * (`{ kind:'submit', cardId, data:{ selected } }`) with the checked ids in
206
- * input order. Emits `ready` on mount and `error` for an unusable definition.
207
- */
208
- export function TasksCard(props: TasksCardProps): JSX.Element {
209
- const merged = mergeProps({ cardId: 'kai-tasks' }, props);
210
- const [local] = splitProps(merged, [
211
- 'data', 'cardId', 'heading', 'host', 'hostElement', 'class', 'resolution',
212
- 'value', 'defaultValue', 'disabled', 'readonly', 'onValueChange', 'controllerRef',
213
- ]);
214
-
215
- const ctxHost = useCardHost();
216
- const uid = createUniqueId();
217
-
218
- const emit = (event: CardEvent): void => {
219
- const h = local.host ?? ctxHost;
220
- if (h) h.emit(event);
221
- else if (local.hostElement) emitCardEvent(local.hostElement, event);
222
- };
223
-
224
- const normalized = createMemo(() => normalizeTasks(local.data?.tasks));
225
- const valid = createMemo(() => normalized().error === undefined);
226
- const errorMessage = createMemo(() => normalized().error ?? '');
227
- const tasks = createMemo(() => normalized().tasks);
228
- const data = createMemo<TasksCardData>(() => local.data ?? DEFAULT_DATA);
229
-
230
- const [selected, setSelected] = createSignal<Set<string>>(new Set());
231
-
232
- const res = useCardResolution({ prop: () => local.resolution, data: () => local.data });
233
-
234
- // Only ids that exist in the current task list (drop unknown ids defensively).
235
- const validIds = (ids: string[]): string[] => {
236
- const known = new Set(tasks().map((t) => t.id));
237
- return ids.filter((id) => known.has(id));
238
- };
239
-
240
- // Seed selection from `value` (controlled) > `defaultValue` > per-task `checked`,
241
- // when a NEW definition arrives.
242
- createEffect(
243
- on(
244
- () => local.data,
245
- () => {
246
- const seedIds = local.value ?? local.defaultValue ?? initialSelected(tasks());
247
- setSelected(new Set(validIds(seedIds)));
248
- },
249
- ),
250
- );
251
-
252
- // Controlled selection: when the consumer drives `value`, mirror it into the set
253
- // (the controlled prop wins). Deferred so mount's seed runs first.
254
- createEffect(on(() => local.value, (v) => {
255
- if (!v) return;
256
- setSelected(new Set(validIds(v)));
257
- }, { defer: true }));
258
-
259
- // Fire the live change signal whenever the selection set changes (distinct from
260
- // the terminal submit). Deferred so the initial seed doesn't emit.
261
- createEffect(on(selected, (s) => {
262
- local.onValueChange?.({ value: selectedInOrder(tasks(), s) });
263
- }, { defer: true }));
264
-
265
- // ready / error lifecycle emits.
266
- createEffect(
267
- on(valid, (ok) => {
268
- if (ok) emit({ kind: 'ready', cardId: local.cardId });
269
- else emit({ kind: 'error', cardId: local.cardId, message: errorMessage() });
270
- }),
271
- );
272
-
273
- const groupDisabled = (): boolean => local.disabled === true;
274
- // Display-only: block all toggling/confirm and drop the interactive affordances,
275
- // without the dimmed/`disabled` look.
276
- const readOnly = (): boolean => local.readonly === true;
277
-
278
- const count = createMemo(() => selected().size);
279
- // `progress` mode = the onboarding-checklist look: a header `done / total`
280
- // count, circular indicators, no confirm button. Same selection model.
281
- const progress = createMemo(() => isProgressMode(data()));
282
- const progressN = createMemo(() => progressCount(tasks(), selected()));
283
- const confirmLabel = () => data().confirmLabel ?? 'Confirm';
284
- const masterState = createMemo(() => selectAllState(tasks(), selected()));
285
- const showMaster = createMemo(() => showSelectAll(data(), tasks()));
286
- const reason = createMemo(() => confirmReason(data(), count()));
287
- const confirmEnabled = createMemo(() => canConfirm(data(), count()) && !res.isResolved() && !groupDisabled() && !readOnly());
288
-
289
- // Apply one id to a selection set, honoring the max gate (mutates+returns `next`).
290
- const applyToggle = (next: Set<string>, id: string, on: boolean): Set<string> => {
291
- if (on) {
292
- // Respect max: block adding past max.
293
- if (isMaxReached(data(), next.size) && !next.has(id)) return next;
294
- next.add(id);
295
- } else {
296
- next.delete(id);
297
- }
298
- return next;
299
- };
300
-
301
- const toggle = (id: string, on: boolean): void => {
302
- if (res.isResolved() || groupDisabled() || readOnly()) return;
303
- setSelected(applyToggle(new Set(selected()), id, on));
304
- };
305
-
306
- const toggleAll = (on: boolean): void => {
307
- if (res.isResolved() || groupDisabled() || readOnly()) return;
308
- const next = new Set(selected());
309
- for (const id of toggleableIds(tasks())) {
310
- if (on) next.add(id);
311
- else next.delete(id);
312
- }
313
- setSelected(next);
314
- };
315
-
316
- const onConfirm = (): void => {
317
- if (!confirmEnabled()) return;
318
- const result: TasksCardResult = { selected: selectedInOrder(tasks(), selected()) };
319
- emit({ kind: 'submit', cardId: local.cardId, data: result });
320
- res.setLocal({ kind: 'submit', data: result });
321
- };
322
-
323
- // Dismiss: emit `dismiss` AND optimistically flip to a `dismissed` resolution so
324
- // the card collapses to its re-openable stub immediately.
325
- const onDismiss = (): void => {
326
- if (res.isResolved()) return;
327
- emit({ kind: 'dismiss', cardId: local.cardId });
328
- res.setLocal({ kind: 'dismissed' });
329
- };
330
- const onReopen = (): void => emit({ kind: 'reopen', cardId: local.cardId });
331
-
332
- // Imperative controller (Pattern C): hand the facade a handle over the tasks
333
- // card's latent selection model. select sets the checked ids local-only (no
334
- // submit); toggle drives one row; send confirms (same path as Confirm); focus
335
- // targets the group; dismiss/reopen drive the stub.
336
- onMount(() => {
337
- local.controllerRef?.({
338
- select: (taskIds) => {
339
- if (res.isResolved() || groupDisabled() || readOnly()) return;
340
- if (taskIds === undefined) { toggleAll(true); return; }
341
- // Build the set fresh, honoring max + disabled per id (skip disabled rows).
342
- const next = new Set<string>();
343
- const toggleable = new Set(toggleableIds(tasks()));
344
- for (const id of validIds(taskIds)) {
345
- if (!toggleable.has(id)) continue; // skip per-task-disabled rows
346
- applyToggle(next, id, true);
347
- }
348
- setSelected(next);
349
- },
350
- toggle: (taskId, checked) => {
351
- // No explicit `checked` → flip the current state.
352
- const on = checked ?? !selected().has(taskId);
353
- toggle(taskId, on);
354
- },
355
- send: () => onConfirm(),
356
- focus: (options) => {
357
- const root = local.hostElement?.shadowRoot ?? document;
358
- const group = root.querySelector<HTMLElement>('[role="group"]');
359
- // Prefer the select-all checkbox (it's the first labelled input), else the
360
- // first row's checkbox; fall back to the group container itself.
361
- const firstInput = group?.querySelector<HTMLElement>('input[type="checkbox"]');
362
- (firstInput ?? group)?.focus(options);
363
- },
364
- dismiss: () => onDismiss(),
365
- reopen: () => onReopen(),
366
- });
367
- });
368
-
369
- // Surface the resolved state for host styling. Only a `submit` resolution is the
370
- // "submitted" state; a deferred `dismissed` (or `expired`) is not.
371
- createEffect(() => {
372
- const el = local.hostElement;
373
- if (!el) return;
374
- if (res.resolution()?.kind === 'submit') el.setAttribute('data-kai-resolved', 'submitted');
375
- else el.removeAttribute('data-kai-resolved');
376
- });
377
-
378
- const resolvedSummary = createMemo(() => {
379
- const r = res.resolution();
380
- if (!r || r.kind !== 'submit') return undefined;
381
- const sel = (r.data as { selected?: unknown })?.selected;
382
- const ids: string[] = Array.isArray(sel) ? (sel as string[]) : [];
383
- const all = tasks();
384
- const chosen = all.filter((t) => ids.includes(t.id)).map((t) => t.label);
385
- return { count: chosen.length, total: all.length, labels: chosen };
386
- });
387
-
388
- const reasonId = `kai-tl-reason-${uid}`;
389
- const countId = `kai-tl-count-${uid}`;
390
- const progressCountId = `kai-tl-progress-${uid}`;
391
- const progressHeadingId = `kai-tl-heading-${uid}`;
392
- const headingText = () => local.heading ?? local.data?.heading;
393
-
394
- return (
395
- <Show when={valid()} fallback={<Card heading={local.heading} errorMessage={errorMessage()} />}>
396
- <ErrorBoundary
397
- fallback={() => {
398
- emit({ kind: 'error', cardId: local.cardId, message: 'The card failed to render.' });
399
- return <Card heading={local.heading} errorMessage="The card failed to render." />;
400
- }}
401
- >
402
- <Show
403
- when={!res.isDeferred()}
404
- fallback={
405
- <DismissedStub type={TASKS_CARD_TYPE} title={local.heading ?? local.data?.heading} onReopen={onReopen} />
406
- }
407
- >
408
- <Card
409
- // In `progress` mode the heading + count render as a custom in-body row
410
- // (so the count can sit right-aligned beside the heading), so the Card
411
- // chrome's own heading is suppressed.
412
- heading={progress() ? undefined : headingText()}
413
- actions={
414
- // `progress` mode is confirm-less: checking a row IS the action.
415
- // `readonly` is display-only, so there's no confirm/dismiss row either.
416
- progress() || res.isResolved() || readOnly() ? undefined : (
417
- <div class="flex w-full flex-wrap items-center justify-between gap-2">
418
- <Show when={local.data?.dismissible === true}>
419
- {/* The contract `dismiss` verb — a footer ACTION (it emits
420
- `{kind:'dismiss'}` and collapses the card to a re-openable
421
- stub), not the chrome close in `Card`'s own `dismissible`
422
- prop, which the contract cards deliberately never set.
423
- Labelled rather than a bare ghost ✕: every other control in
424
- this row says what it does, and an unlabelled 28px glyph
425
- 300px from the primary button reads as stray chrome. Same
426
- shape in all four cards — `form` already looked like this.
427
- `aria-label` is kept (redundant with the text) so the
428
- element tests that select on it keep working. */}
429
- <Button
430
- type="button"
431
- variant="ghost"
432
- aria-label="Dismiss"
433
- onClick={onDismiss}
434
- >
435
- Dismiss
436
- </Button>
437
- </Show>
438
- <span id={countId} aria-live="polite" class="text-xs text-muted-foreground">
439
- {count()} selected
440
- </span>
441
- <div class="ml-auto flex items-center gap-2">
442
- <Show when={reason()}>
443
- <span id={reasonId} class="sr-only">
444
- {reason()}
445
- </span>
446
- </Show>
447
- <Button
448
- type="button"
449
- disabled={!confirmEnabled()}
450
- aria-describedby={reason() ? reasonId : undefined}
451
- onClick={onConfirm}
452
- >
453
- {confirmLabel()}
454
- </Button>
455
- </div>
456
- </div>
457
- )
458
- }
459
- >
460
- <Show
461
- when={!res.isResolved()}
462
- fallback={<TasksResolved summary={resolvedSummary()!} optimistic={res.isOptimistic()} />}
463
- >
464
- <Show when={progress()}>
465
- <ProgressChecklist
466
- heading={headingText()}
467
- headingId={progressHeadingId}
468
- countId={progressCountId}
469
- done={progressN().done}
470
- total={progressN().total}
471
- tasks={tasks()}
472
- uid={uid}
473
- isChecked={(id) => selected().has(id)}
474
- isBlocked={(task) =>
475
- groupDisabled() || task.disabled === true ||
476
- (!selected().has(task.id) && isMaxReached(data(), count()))
477
- }
478
- onToggle={(id, on) => toggle(id, on)}
479
- groupClass={local.class}
480
- maxNote={data().max !== undefined ? data().max : undefined}
481
- readonly={readOnly()}
482
- />
483
- </Show>
484
- <Show when={!progress()}>
485
- <div
486
- role="group"
487
- aria-label={local.heading ?? local.data?.heading ?? 'Tasks'}
488
- aria-readonly={readOnly() ? 'true' : undefined}
489
- class={cn('flex flex-col', local.class)}
490
- onKeyDown={(e) => {
491
- // Enter anywhere in the card (off a checkbox) confirms when enabled.
492
- if (e.key !== 'Enter') return;
493
- const target = e.target as HTMLElement;
494
- if (target.tagName === 'INPUT') return;
495
- if (confirmEnabled()) onConfirm();
496
- }}
497
- >
498
- <div class="divide-y divide-border overflow-hidden rounded-lg border border-border">
499
- <Show when={showMaster()}>
500
- {(() => {
501
- const indeterminate = () => masterState() === 'indeterminate';
502
- return (
503
- <label
504
- class={cn(
505
- 'flex items-center gap-3 px-3 py-2.5 text-sm font-medium transition-colors',
506
- readOnly() ? 'cursor-default' : 'cursor-pointer',
507
- masterState() === 'checked'
508
- ? 'bg-accent text-accent-foreground'
509
- : readOnly()
510
- ? 'text-foreground'
511
- : 'text-foreground hover:bg-muted/50',
512
- )}
513
- >
514
- {/* SQUARE `Checkbox` (the `.kai-checkbox` look), and the checklist below draws a
515
- ROUND lucide Circle/CircleCheck instead. Deliberate, not drift: this
516
- is `select` mode — a pick-list whose rows are a pending selection that
517
- only commits when the confirm button fires, which is what a checkbox
518
- means everywhere else. `progress` mode has no confirm and toggling a
519
- row IS the action, so it uses the done/not-done affordance of a todo
520
- list. See the D-2 row in
521
- docs/superpowers/plans/2026-08-25-form-control-primitives.md; owner has
522
- not ruled, so do not converge these on your own. */}
523
- <Checkbox
524
- checked={masterState() === 'checked'}
525
- disabled={groupDisabled() || readOnly()}
526
- indeterminate={indeterminate()}
527
- aria-checked={indeterminate() ? 'mixed' : masterState() === 'checked'}
528
- onChange={(e) => toggleAll(e.currentTarget.checked)}
529
- />
530
- <span>Select all</span>
531
- </label>
532
- );
533
- })()}
534
- </Show>
535
-
536
- <For each={tasks()}>
537
- {(task) => {
538
- const checked = () => selected().has(task.id);
539
- const blocked = () =>
540
- groupDisabled() || task.disabled || (!checked() && isMaxReached(data(), count()));
541
- const descId = `kai-tl-desc-${uid}-${task.id}`;
542
- return (
543
- <label
544
- class={cn(
545
- 'flex items-start gap-3 px-3 py-2.5 text-sm transition-colors',
546
- readOnly()
547
- ? 'cursor-default'
548
- : blocked()
549
- ? 'cursor-not-allowed opacity-60'
550
- : 'cursor-pointer hover:bg-muted/50',
551
- checked() && !blocked()
552
- ? 'bg-accent font-medium text-accent-foreground'
553
- : 'text-foreground',
554
- )}
555
- data-task-id={task.id}
556
- >
557
- <Checkbox
558
- class="mt-0.5"
559
- checked={checked()}
560
- disabled={blocked() || readOnly()}
561
- aria-disabled={blocked() ? 'true' : undefined}
562
- aria-describedby={task.description ? descId : undefined}
563
- onChange={(e) => toggle(task.id, e.currentTarget.checked)}
564
- />
565
- <span class="flex flex-col gap-0.5">
566
- <span>{task.label}</span>
567
- <Show when={task.description}>
568
- <span id={descId} class="text-xs font-normal text-muted-foreground">
569
- {task.description}
570
- </span>
571
- </Show>
572
- </span>
573
- </label>
574
- );
575
- }}
576
- </For>
577
- </div>
578
-
579
- <Show when={data().max !== undefined}>
580
- <p class="pt-1 text-xs text-muted-foreground">Up to {data().max} selected.</p>
581
- </Show>
582
- </div>
583
- </Show>
584
- </Show>
585
- </Card>
586
- </Show>
587
- </ErrorBoundary>
588
- </Show>
589
- );
590
- }
591
-
592
- // ─────────────────────────────────────────────────────────────────────────────
593
- // Onboarding-checklist (`mode: 'progress'`) presenter: a header `done / total`
594
- // count + circular indicators + per-item title/description, no confirm button.
595
- // Drives the same selection model, where toggling a row IS the action.
596
- // ─────────────────────────────────────────────────────────────────────────────
597
-
598
- function ProgressChecklist(props: {
599
- heading?: string;
600
- headingId: string;
601
- countId: string;
602
- done: number;
603
- total: number;
604
- tasks: TasksTask[];
605
- uid: string;
606
- isChecked: (id: string) => boolean;
607
- isBlocked: (task: TasksTask) => boolean;
608
- onToggle: (id: string, on: boolean) => void;
609
- groupClass?: string;
610
- maxNote?: number;
611
- /** Display-only: rows aren't focusable/toggleable and show the default cursor. */
612
- readonly?: boolean;
613
- }): JSX.Element {
614
- return (
615
- <div class={cn('flex flex-col gap-3', props.groupClass)}>
616
- <Show when={props.heading}>
617
- <div class="flex items-center justify-between gap-3">
618
- <span
619
- id={props.headingId}
620
- class="text-title font-semibold tracking-tight text-foreground"
621
- >
622
- {props.heading}
623
- </span>
624
- <span
625
- id={props.countId}
626
- aria-live="polite"
627
- class="shrink-0 text-sm font-medium tabular-nums text-muted-foreground"
628
- >
629
- {props.done} / {props.total}
630
- </span>
631
- </div>
632
- </Show>
633
-
634
- {/* Thin progress bar under the heading: filled to done / total. Named off the
635
- checklist heading (no duplicate caption), or a generic label when headless. */}
636
- <ProgressBar
637
- value={props.done}
638
- max={props.total}
639
- tone="success"
640
- aria-labelledby={props.heading ? props.headingId : undefined}
641
- aria-label={props.heading ? undefined : 'Task progress'}
642
- />
643
-
644
- <ul
645
- aria-labelledby={props.heading ? props.headingId : undefined}
646
- aria-label={props.heading ? undefined : 'Checklist'}
647
- class="flex flex-col gap-1"
648
- >
649
- <For each={props.tasks}>
650
- {(task) => {
651
- const checked = () => props.isChecked(task.id);
652
- const blocked = () => props.isBlocked(task);
653
- const descId = `kai-tl-pdesc-${props.uid}-${task.id}`;
654
- return (
655
- <li>
656
- <label
657
- class={cn(
658
- 'group flex items-start gap-3 rounded-lg px-2.5 py-2 text-sm transition-colors',
659
- // Keyboard focus ring (kit standard, inset so it stays within the
660
- // row). focus-visible only, so a mouse click that parks focus on the
661
- // row doesn't leave a noisy persistent outline — and it makes a
662
- // Tab-focused completed row's open description perceivable. Dropped
663
- // entirely when readonly (the row isn't focusable then).
664
- //
665
- // TWO tab stops exist per row and the ring has to cover both.
666
- // `focus-visible:` matches only when the LABEL itself is focused,
667
- // which is completed rows only (the `tabindex` below). Every row's
668
- // other — and for an incomplete row, only — tab stop is the sr-only
669
- // checkbox inside, so without `has-[:focus-visible]:` tabbing to an
670
- // unchecked row put focus on an off-screen input with no indicator
671
- // anywhere on screen. Both halves stay on the focus-VISIBLE axis on
672
- // purpose: `focus-within:` would also fire for a mouse click (which
673
- // forwards focus from the label to the checkbox), which is exactly
674
- // the persistent-outline noise the paragraph above rejects. The
675
- // description reveal below uses `group-focus-within:` because a
676
- // hover-or-focus reveal wants the looser condition.
677
- !props.readonly &&
678
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring',
679
- !props.readonly &&
680
- 'has-[:focus-visible]:outline-none has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-inset has-[:focus-visible]:ring-ring',
681
- props.readonly
682
- ? 'cursor-default'
683
- : blocked()
684
- ? 'cursor-not-allowed opacity-60'
685
- : 'cursor-pointer hover:bg-muted/50',
686
- )}
687
- data-task-id={task.id}
688
- // Completed rows hide their description until hover/focus, so make the
689
- // row itself focusable to drive the focus-reveal (group-focus-within).
690
- // Incomplete rows — and every row when readonly — stay unfocusable.
691
- // Expose the label + description to AT.
692
- tabindex={!props.readonly && checked() ? 0 : undefined}
693
- aria-label={checked() ? task.label : undefined}
694
- aria-describedby={checked() && task.description ? descId : undefined}
695
- >
696
- <input
697
- type="checkbox"
698
- class="sr-only"
699
- checked={checked()}
700
- disabled={blocked() || props.readonly}
701
- aria-disabled={blocked() ? 'true' : undefined}
702
- aria-describedby={task.description ? descId : undefined}
703
- onChange={(e) => props.onToggle(task.id, e.currentTarget.checked)}
704
- />
705
- <span
706
- class={cn(
707
- 'mt-0.5 shrink-0 text-muted-foreground',
708
- // Completed rows: the check gently scales on hover.
709
- checked() && 'motion-safe:transition-transform motion-safe:group-hover:scale-110',
710
- )}
711
- aria-hidden="true"
712
- >
713
- {/* ROUND, where `select` mode uses the square `Checkbox`. Deliberate:
714
- this mode has no confirm button, so ticking a row IS the action and the
715
- row is done-or-not rather than selected-or-not — the todo-list
716
- affordance, which is how this mode has been described since it landed
717
- (see the `mode` argType in tasks-card.stories.tsx and the JSDoc on
718
- src/elements/tasks.tsx). D-2 in
719
- docs/superpowers/plans/2026-08-25-form-control-primitives.md tracks
720
- whether to keep the split; unruled, so leave both. NOTE the cost: the
721
- icon replaces the visible native control, which is why the real input
722
- above is `sr-only` and why the row's focus ring has to be driven by
723
- `has-[:focus-visible]:`. Converging on `Checkbox` would take that
724
- hazard away with it. */}
725
- <Show
726
- when={checked()}
727
- fallback={<Circle size={18} />}
728
- >
729
- <CircleCheck size={18} class="text-foreground" />
730
- </Show>
731
- </span>
732
- <span class="flex min-w-0 flex-col gap-0.5">
733
- <span
734
- class={cn(
735
- 'font-medium text-foreground',
736
- // Completed: strike through + muted, brightening on hover.
737
- checked() && 'line-through opacity-70 motion-safe:transition-opacity motion-safe:group-hover:opacity-100',
738
- )}
739
- >
740
- {task.label}
741
- </span>
742
- <Show when={task.description}>
743
- <Show
744
- when={checked()}
745
- fallback={
746
- <span id={descId} class="text-xs font-normal text-muted-foreground">
747
- {task.description}
748
- </span>
749
- }
750
- >
751
- {/* Completed: collapse the description and reveal it on hover or
752
- keyboard focus via the grid-rows height trick. Height-collapse
753
- keeps the text in the DOM + a11y tree (unlike display:none). */}
754
- <div class="grid grid-rows-[0fr] group-hover:grid-rows-[1fr] group-focus-within:grid-rows-[1fr] motion-safe:transition-[grid-template-rows] motion-safe:duration-200">
755
- <span
756
- id={descId}
757
- class="overflow-hidden text-xs font-normal text-muted-foreground opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 motion-safe:transition-opacity"
758
- >
759
- {task.description}
760
- </span>
761
- </div>
762
- </Show>
763
- </Show>
764
- </span>
765
- </label>
766
- </li>
767
- );
768
- }}
769
- </For>
770
- </ul>
771
-
772
- <Show when={props.maxNote !== undefined}>
773
- <p class="text-xs text-muted-foreground">Up to {props.maxNote} selected.</p>
774
- </Show>
775
- </div>
776
- );
777
- }
778
-
779
- // ─────────────────────────────────────────────────────────────────────────────
780
- // Read-only resolved summary presenter.
781
- // ─────────────────────────────────────────────────────────────────────────────
782
-
783
- function TasksResolved(props: {
784
- summary: { count: number; total: number; labels: string[] };
785
- optimistic: boolean;
786
- }): JSX.Element {
787
- return (
788
- <div class="flex flex-col gap-2" role={props.optimistic ? 'status' : undefined}>
789
- <p class="flex items-center gap-2 text-sm font-medium text-foreground">
790
- <Check size={16} aria-hidden="true" />
791
- <span>Selected {props.summary.count} of {props.summary.total}</span>
792
- </p>
793
- <Show when={props.summary.labels.length > 0}
794
- fallback={<p class="text-sm text-muted-foreground">None selected</p>}>
795
- <ul class="list-disc pl-5 text-sm text-foreground">
796
- <For each={props.summary.labels}>{(l) => <li>{l}</li>}</For>
797
- </ul>
798
- </Show>
799
- </div>
800
- );
801
- }