@kitn.ai/ui 0.27.0 → 0.29.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 (612) hide show
  1. package/README.md +10 -2
  2. package/dist/{Icon-BnFKqqtY.js → Icon-DObhsRtm.js} +1 -1
  3. package/dist/{action-icons-CBskfBMz.js → action-icons-CcgNN2oT.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-CjRU3JgV.js +1 -0
  7. package/dist/arrow-left-Bnpb1UEW.js +1 -0
  8. package/dist/{artifact-CvXEm1lS.js → artifact-Bwt7OgcR.js} +1 -1
  9. package/dist/{attachments-C43ZegEq.js → attachments-Qr4kg-2b.js} +1 -1
  10. package/dist/{audio-visualizer-B-79y1Tj.js → audio-visualizer-DToYdfSc.js} +1 -1
  11. package/dist/{badge-BpUbq8c0.js → badge-CdEu_jn2.js} +1 -1
  12. package/dist/{bell-sn17Ip9v.js → bell-DQAAOpDz.js} +1 -1
  13. package/dist/{button-BH6rN0U-.js → button-DkuOnGLy.js} +1 -1
  14. package/dist/{card-renderer-Cb1gQmth.js → card-renderer-Jx70m6_l.js} +1 -1
  15. package/dist/{card-routing-DifQgS7n.js → card-routing-0YidER_3.js} +1 -1
  16. package/dist/check-njkVdZu2.js +1 -0
  17. package/dist/{checkbox-Dc9Yov_B.js → checkbox-D7iRB3nL.js} +1 -1
  18. package/dist/{checkbox-group-B1kDLLYk.js → checkbox-group-B2_rpoPM.js} +1 -1
  19. package/dist/chevron-down-B72s6PXR.js +1 -0
  20. package/dist/chevron-right-BatuHzUm.js +1 -0
  21. package/dist/{choice-card-BT3c1S8g.js → choice-card-m0BYqqOK.js} +1 -1
  22. package/dist/circle-check-B62pODB3.js +1 -0
  23. package/dist/{circle-x-wobWkoSx.js → circle-x-BPG0iPst.js} +1 -1
  24. package/dist/circle-zx0ByzY9.js +1 -0
  25. package/dist/code-block-ClMLKb7C.js +1 -0
  26. package/dist/{collapsible-CPJbf6FM.js → collapsible-B4DlWicL.js} +1 -1
  27. package/dist/components/chat-thread.d.ts +89 -1
  28. package/dist/components/conversation-item.d.ts +16 -0
  29. package/dist/components/conversation-panel.d.ts +29 -0
  30. package/dist/components/home-panel.d.ts +34 -0
  31. package/dist/components/widget-tab-bar.d.ts +16 -0
  32. package/dist/{composer-CjngLzal.js → composer-sQ0HcvyG.js} +3 -3
  33. package/dist/{confirm-card-DCx_A4bU.js → confirm-card-rQWDQsnC.js} +1 -1
  34. package/dist/construct-cli.es.js +185 -17
  35. package/dist/construct.d.ts +5 -0
  36. package/dist/construct.js +327 -0
  37. package/dist/{context-BY8V-Nlp.js → context-0kg4ZX1J.js} +1 -1
  38. package/dist/controllable-CnGpMF6r.js +1 -0
  39. package/dist/conversation-item-BxwQLaFJ.js +1 -0
  40. package/dist/conversation-list-BCfGN1JU.js +1 -0
  41. package/dist/{copy-B6DO4PqB.js → copy-n9u9rqpi.js} +1 -1
  42. package/dist/core-C8fzo39E.js +1 -12
  43. package/dist/{create-tween-CnMHviKB.js → create-tween-C-q-JCM-.js} +1 -1
  44. package/dist/{create-tween-D1aiGZZh.js → create-tween-CRrJXxBd.js} +1 -1
  45. package/dist/{create-tween-BPzaefTp.js → create-tween-DZ3RRDHD.js} +1 -1
  46. package/dist/{create-tween-DUSQUKpr.js → create-tween-uPkArjIG.js} +1 -1
  47. package/dist/custom-elements.json +51 -2
  48. package/dist/{default-input-CucQEOqH.js → default-input-CaMrJkgH.js} +1 -1
  49. package/dist/define-By-uL588.js +1 -0
  50. package/dist/define.js +2 -2
  51. package/dist/define.server.js +2 -2
  52. package/dist/{disclosure-CbLtajUQ.js → disclosure-WUImBbDv.js} +1 -1
  53. package/dist/{dropdown-BwhViJFd.js → dropdown-wZVeJOMd.js} +1 -1
  54. package/dist/elements/agent-card.js +1 -1
  55. package/dist/elements/artifact.js +1 -1
  56. package/dist/elements/attachments.js +1 -1
  57. package/dist/elements/audio-visualizer.js +1 -1
  58. package/dist/elements/avatar.js +1 -1
  59. package/dist/elements/badge.js +1 -1
  60. package/dist/elements/button.js +1 -1
  61. package/dist/elements/card.js +1 -1
  62. package/dist/elements/cards.js +1 -1
  63. package/dist/elements/chain-of-thought.js +1 -1
  64. package/dist/elements/chat-scope-picker.js +1 -1
  65. package/dist/elements/chat-workspace.js +1 -1
  66. package/dist/elements/chat.js +1 -1
  67. package/dist/elements/checkbox-group.js +1 -1
  68. package/dist/elements/checkbox.js +1 -1
  69. package/dist/elements/checkpoint.js +1 -1
  70. package/dist/elements/choice.js +1 -1
  71. package/dist/elements/coachmark.js +1 -1
  72. package/dist/elements/code-block.js +1 -1
  73. package/dist/elements/command.js +1 -1
  74. package/dist/elements/compare.js +1 -1
  75. package/dist/elements/composer.js +1 -1
  76. package/dist/elements/confirm-card.js +1 -1
  77. package/dist/elements/context-meter.js +1 -1
  78. package/dist/elements/conversation-item.js +1 -1
  79. package/dist/elements/conversation-list.js +1 -1
  80. package/dist/elements/dialog.js +1 -1
  81. package/dist/elements/dock.js +3 -3
  82. package/dist/elements/dropdown.js +1 -1
  83. package/dist/elements/editable-label.js +1 -1
  84. package/dist/elements/embed.js +1 -1
  85. package/dist/elements/empty.js +1 -1
  86. package/dist/elements/feedback-bar.js +1 -1
  87. package/dist/elements/file-tree.js +1 -1
  88. package/dist/elements/file-upload.js +1 -1
  89. package/dist/elements/form.js +1 -1
  90. package/dist/elements/hover-card.js +1 -1
  91. package/dist/elements/icon.js +1 -1
  92. package/dist/elements/image.js +1 -1
  93. package/dist/elements/input.js +1 -1
  94. package/dist/elements/kbd.js +1 -1
  95. package/dist/elements/link-preview.js +1 -1
  96. package/dist/elements/loader.js +1 -1
  97. package/dist/elements/markdown.js +1 -1
  98. package/dist/elements/menu.js +1 -1
  99. package/dist/elements/message-skills.js +1 -1
  100. package/dist/elements/message.js +1 -1
  101. package/dist/elements/model-switcher.js +1 -1
  102. package/dist/elements/nav.js +1 -1
  103. package/dist/elements/notice.js +1 -1
  104. package/dist/elements/pane-grid.js +1 -1
  105. package/dist/elements/pane-group.js +1 -1
  106. package/dist/elements/pane.js +1 -1
  107. package/dist/elements/popover.js +1 -1
  108. package/dist/elements/progress-bar.js +1 -1
  109. package/dist/elements/prompt-dock.js +1 -1
  110. package/dist/elements/prompt-input.js +1 -1
  111. package/dist/elements/prompt-suggestions.js +1 -1
  112. package/dist/elements/radio-group.js +1 -1
  113. package/dist/elements/reasoning.js +1 -1
  114. package/dist/elements/remote.js +1 -1
  115. package/dist/elements/resizable.js +1 -1
  116. package/dist/elements/response-stream.js +1 -1
  117. package/dist/elements/screen.js +1 -1
  118. package/dist/elements/scroll-area.js +1 -1
  119. package/dist/elements/scroll-button.js +1 -1
  120. package/dist/elements/search.js +1 -1
  121. package/dist/elements/segmented.js +1 -1
  122. package/dist/elements/select.js +1 -1
  123. package/dist/elements/separator.js +1 -1
  124. package/dist/elements/setting-item.js +1 -1
  125. package/dist/elements/settings-group.js +1 -1
  126. package/dist/elements/skeleton.js +1 -1
  127. package/dist/elements/slider.js +1 -1
  128. package/dist/elements/source.js +1 -1
  129. package/dist/elements/status.js +1 -1
  130. package/dist/elements/switch.js +1 -1
  131. package/dist/elements/tabs.js +1 -1
  132. package/dist/elements/tasks.js +1 -1
  133. package/dist/elements/text-shimmer.js +1 -1
  134. package/dist/elements/thinking-bar.js +1 -1
  135. package/dist/elements/thread.js +1 -1
  136. package/dist/elements/toast.js +1 -1
  137. package/dist/elements/tool.js +1 -1
  138. package/dist/elements/tooltip.js +1 -1
  139. package/dist/elements/voice-input.js +1 -1
  140. package/dist/elements/voice-output.js +1 -1
  141. package/dist/elements.d.ts +20 -4
  142. package/dist/{ellipsis-DFr4Vqr3.js → ellipsis-CbOpJnU3.js} +1 -1
  143. package/dist/{embed-5s_vU4J0.js → embed-CrfjkbUG.js} +1 -1
  144. package/dist/engine-javascript-C1x7zo1_.js +1 -141
  145. package/dist/{external-link-u9d85ORQ.js → external-link-ByXAwBBQ.js} +1 -1
  146. package/dist/{file-text-CX7_x42o.js → file-text-DMib2qwt.js} +1 -1
  147. package/dist/{file-tree-D3kBjXI5.js → file-tree-CJqM2aP7.js} +1 -1
  148. package/dist/{folder-V-YdIL8f.js → folder-_BAb929C.js} +1 -1
  149. package/dist/{form-BRNUMCN2.js → form-DSZgZQZk.js} +1 -1
  150. package/dist/{hover-card-DaeiYrTA.js → hover-card-BQbul9eq.js} +1 -1
  151. package/dist/{icon-BpixdZNq.js → icon-CdcfRhYI.js} +1 -1
  152. package/dist/index.d.ts +3 -1
  153. package/dist/index.js +2842 -2703
  154. package/dist/index.server.js +2820 -2681
  155. package/dist/{info-8mFsIjS3.js → info-DsFjGuI_.js} +1 -1
  156. package/dist/{input-d1Yuu-hz.js → input-DKbmkMos.js} +1 -1
  157. package/dist/kai.es.js +1 -1
  158. package/dist/{kbd-961zMPFB.js → kbd-PvdGhX4s.js} +1 -1
  159. package/dist/{link-preview-DIIbV2Sd.js → link-preview-DbM1866N.js} +1 -1
  160. package/dist/{link-DlZZBGaR.js → link-zF8PzWfF.js} +1 -1
  161. package/dist/{loader-YQszHFaW.js → loader-BM4CEz4G.js} +1 -1
  162. package/dist/{markdown-CVk1MPsj.js → markdown-LMvmAyBk.js} +7 -7
  163. package/dist/mcp.es.js +79 -5
  164. package/dist/{message-CwKVEdZg.js → message-BSsgvHvf.js} +1 -1
  165. package/dist/{message-DS8lzHc1.js → message-BYZECyek.js} +1 -1
  166. package/dist/message-circle-DruwObfX.js +1 -0
  167. package/dist/message-square-BG6q6mlm.js +1 -0
  168. package/dist/{minimize-2-UEZmP2QT.js → minimize-2-BQRoBV1V.js} +1 -1
  169. package/dist/{model-switcher-Kk1jEQ5t.js → model-switcher-CMpCOYcB.js} +1 -1
  170. package/dist/{overlay-C1od6LOz.js → overlay-Cb-MkyDa.js} +1 -1
  171. package/dist/{panel-right-ryET0yyn.js → panel-right-i8warFxT.js} +1 -1
  172. package/dist/{paperclip-BDNoZFJP.js → paperclip-ByY3UVO6.js} +1 -1
  173. package/dist/play-BvKKq3fX.js +1 -0
  174. package/dist/primitives/conversation-store.d.ts +54 -0
  175. package/dist/{progress-bar-BvYX0aoy.js → progress-bar-jVAHvMUf.js} +1 -1
  176. package/dist/{prompt-suggestion-BRFu2lcu.js → prompt-suggestion-CD-qtNgC.js} +1 -1
  177. package/dist/{radio-DcL23cNJ.js → radio-BsoBMhkF.js} +1 -1
  178. package/dist/react/index.d.ts +393 -0
  179. package/dist/react.js +20 -20
  180. package/dist/{reasoning-Cackq4Rh.js → reasoning-4kBPtlTx.js} +1 -1
  181. package/dist/register-impl-B1hLkrI8.js +424 -0
  182. package/dist/{resizable-Cp9HUYih.js → resizable-uPmY9VY-.js} +1 -1
  183. package/dist/{rotate-ccw-0DLRDHH5.js → rotate-ccw-B2xn93py.js} +1 -1
  184. package/dist/{rotate-cw-DOB9IGcU.js → rotate-cw-CMVLoCyH.js} +1 -1
  185. package/dist/{scroll-area-emVmWP4K.js → scroll-area-BqLUo8ZZ.js} +1 -1
  186. package/dist/{scroll-button-CeP_gv1x.js → scroll-button-DslXiJyL.js} +1 -1
  187. package/dist/{select-CWmu00tS.js → select-2cLRtPGT.js} +1 -1
  188. package/dist/{separator-CE6vly6z.js → separator-BWQtNJcM.js} +1 -1
  189. package/dist/{settings-CE-78SvZ.js → settings-BBR63jLg.js} +1 -1
  190. package/dist/{settings-group-ZFWNxFQR.js → settings-group-B2ciy-Iw.js} +1 -1
  191. package/dist/{skeleton-BebdP4mf.js → skeleton-CkHI-HgC.js} +1 -1
  192. package/dist/{slider-BAKRYUlz.js → slider-DDR9U-i0.js} +1 -1
  193. package/dist/{solid-BE5ui6sy.js → solid-BzCFdL25.js} +7720 -7058
  194. package/dist/{solid-DFhsce3O.js → solid-DruVOXnf.js} +5864 -5283
  195. package/dist/solid.d.ts +6 -2
  196. package/dist/solid.js +217 -210
  197. package/dist/solid.server.js +217 -210
  198. package/dist/{source-B0FlguSx.js → source-GEnFF528.js} +1 -1
  199. package/dist/{star-CBMZvLuN.js → star-CilHq8GP.js} +1 -1
  200. package/dist/store-Ciyk6eZG.js +1 -0
  201. package/dist/{switch-CViARZCy.js → switch-KkeQIbuH.js} +1 -1
  202. package/dist/{tasks-card-MjCcOhR_.js → tasks-card-BrN4bggJ.js} +1 -1
  203. package/dist/{text-shimmer-DKlwRF2G.js → text-shimmer-Dcj1MHuq.js} +1 -1
  204. package/dist/{textarea-3ay2Me2-.js → textarea-Dpvbngbg.js} +1 -1
  205. package/dist/theme.tokens.css +28 -0
  206. package/dist/{thumbs-up-DQcu2HMO.js → thumbs-up-CsT9Wzb9.js} +1 -1
  207. package/dist/{toast-store-C6yKOhbk.js → toast-store-tgK6MuMv.js} +1 -1
  208. package/dist/{tool-BCYNlfKy.js → tool-DzUjIBT8.js} +1 -1
  209. package/dist/{tooltip-05zI4hjs.js → tooltip-Bkkg_4t0.js} +1 -1
  210. package/dist/{trash-2-BR1RxGky.js → trash-2-jBKxjGGQ.js} +1 -1
  211. package/dist/{triangle-alert-DHohDOCy.js → triangle-alert-DlQ68ppf.js} +1 -1
  212. package/dist/types.d.ts +48 -3
  213. package/dist/ui/dock.d.ts +29 -0
  214. package/dist/{upload-BbGW6A_u.js → upload-TcAHXv9W.js} +1 -1
  215. package/dist/{url-scheme-policy-DHpoTJwB.js → url-scheme-policy-DR5DgvkM.js} +1 -1
  216. package/dist/{use-card-resolution-CJW4grFa.js → use-card-resolution-DaZqAdWf.js} +1 -1
  217. package/dist/{variant-aurora-xiMPty8f.js → variant-aurora-BhLuYxJR.js} +1 -1
  218. package/dist/{variant-aurora-BUOVgPOB.js → variant-aurora-CNmfHhcx.js} +2 -2
  219. package/dist/{variant-aurora-CUsUJvFI.js → variant-aurora-D6GsdTPA.js} +2 -2
  220. package/dist/{variant-aurora-CW2i4bfr.js → variant-aurora-DbW_OWL2.js} +1 -1
  221. package/dist/{variant-custom-D91HjAKz.js → variant-custom-BRvaNHSi.js} +1 -1
  222. package/dist/{variant-custom-BQtOnmeO.js → variant-custom-BvYHR62b.js} +1 -1
  223. package/dist/{variant-custom-CAnzzppW.js → variant-custom-DMTrEO5w.js} +2 -2
  224. package/dist/{variant-custom-CAm9L-E5.js → variant-custom-DV2x254s.js} +2 -2
  225. package/dist/{variant-wave-Ca1Ls4_y.js → variant-wave-BNMGrDfj.js} +2 -2
  226. package/dist/{variant-wave-uY5crU_K.js → variant-wave-BpDd8t3Z.js} +1 -1
  227. package/dist/{variant-wave-CxX39DKd.js → variant-wave-CyBueXj9.js} +2 -2
  228. package/dist/{variant-wave-DYyzIIZv.js → variant-wave-sp-qwsdI.js} +1 -1
  229. package/dist/x-Z5UntkIJ.js +1 -0
  230. package/frameworks/react/index.tsx +14 -4
  231. package/llms-full.txt +7 -2
  232. package/package.json +16 -16
  233. package/src/elements/element-meta.json +49 -6
  234. package/theme.css +28 -0
  235. package/bin/route.test.js +0 -58
  236. package/dist/arrow-down-Br0qtpsz.js +0 -1
  237. package/dist/arrow-left-Dj7xgE12.js +0 -1
  238. package/dist/check-DPeeMUYx.js +0 -1
  239. package/dist/chevron-down-CHSWk7ZT.js +0 -1
  240. package/dist/chevron-right-B7l_fMgx.js +0 -1
  241. package/dist/circle-Bb0yOpqM.js +0 -1
  242. package/dist/circle-check-BGZpCiz7.js +0 -1
  243. package/dist/code-block-CUQ5mtv0.js +0 -1
  244. package/dist/controllable-D43BKmtX.js +0 -1
  245. package/dist/conversation-list-D4lLU_yS.js +0 -1
  246. package/dist/define-CGGX-7Vg.js +0 -1
  247. package/dist/message-circle-Xf8Q-vZp.js +0 -1
  248. package/dist/message-square-Cxnwgkns.js +0 -1
  249. package/dist/play-OFIvYXUQ.js +0 -1
  250. package/dist/register-impl-C7rENvPK.js +0 -424
  251. package/dist/store-7eoadydQ.js +0 -1
  252. package/dist/x-C5m1JFgi.js +0 -1
  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 -131
  263. package/src/agent-tooling/construct/codegen.ts +0 -1353
  264. package/src/agent-tooling/construct/construct.v1.schema.json +0 -250
  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 -23
  269. package/src/agent-tooling/construct/schema.ts +0 -371
  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 -518
  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 -218
  336. package/src/components/conversation-list.tsx +0 -429
  337. package/src/components/dismissed-stub.tsx +0 -80
  338. package/src/components/embed.tsx +0 -200
  339. package/src/components/empty.tsx +0 -177
  340. package/src/components/feedback-bar.tsx +0 -166
  341. package/src/components/file-tree.tsx +0 -530
  342. package/src/components/file-upload.tsx +0 -167
  343. package/src/components/form-widgets.tsx +0 -525
  344. package/src/components/form.tsx +0 -1296
  345. package/src/components/image.tsx +0 -65
  346. package/src/components/link-preview.tsx +0 -195
  347. package/src/components/loader.tsx +0 -367
  348. package/src/components/markdown.tsx +0 -162
  349. package/src/components/message-skills.tsx +0 -40
  350. package/src/components/message.tsx +0 -765
  351. package/src/components/model-switcher.tsx +0 -132
  352. package/src/components/prompt-input.tsx +0 -188
  353. package/src/components/prompt-suggestion.tsx +0 -150
  354. package/src/components/reasoning.tsx +0 -293
  355. package/src/components/response-compare-types.ts +0 -152
  356. package/src/components/response-compare.tsx +0 -455
  357. package/src/components/response-stream.tsx +0 -109
  358. package/src/components/screen.tsx +0 -181
  359. package/src/components/scroll-button.tsx +0 -93
  360. package/src/components/source.tsx +0 -192
  361. package/src/components/tasks-card.tsx +0 -801
  362. package/src/components/text-shimmer.tsx +0 -37
  363. package/src/components/thinking-bar.tsx +0 -50
  364. package/src/components/thread.tsx +0 -228
  365. package/src/components/toast.tsx +0 -503
  366. package/src/components/tool-classify.ts +0 -26
  367. package/src/components/tool-types.ts +0 -49
  368. package/src/components/tool.tsx +0 -190
  369. package/src/components/use-card-resolution.ts +0 -44
  370. package/src/components/voice-input.tsx +0 -222
  371. package/src/components/voice-output.tsx +0 -242
  372. package/src/components/workspace-shell.tsx +0 -285
  373. package/src/diagnostics/hook.ts +0 -352
  374. package/src/diagnostics/index.ts +0 -82
  375. package/src/diagnostics/report-request.ts +0 -296
  376. package/src/elements/agent-card.tsx +0 -67
  377. package/src/elements/artifact.tsx +0 -194
  378. package/src/elements/attachments.tsx +0 -140
  379. package/src/elements/audio-visualizer.tsx +0 -227
  380. package/src/elements/autoloader.ts +0 -89
  381. package/src/elements/avatar.tsx +0 -33
  382. package/src/elements/badge.tsx +0 -32
  383. package/src/elements/button.tsx +0 -149
  384. package/src/elements/card.tsx +0 -133
  385. package/src/elements/cards.tsx +0 -266
  386. package/src/elements/chain-of-thought.tsx +0 -141
  387. package/src/elements/chat-scope-picker.tsx +0 -65
  388. package/src/elements/chat-types.ts +0 -102
  389. package/src/elements/chat-workspace.tsx +0 -188
  390. package/src/elements/chat.tsx +0 -212
  391. package/src/elements/checkbox-group.tsx +0 -164
  392. package/src/elements/checkbox.tsx +0 -134
  393. package/src/elements/checkpoint.tsx +0 -47
  394. package/src/elements/choice.tsx +0 -100
  395. package/src/elements/coachmark.tsx +0 -90
  396. package/src/elements/code-block.tsx +0 -60
  397. package/src/elements/command.tsx +0 -197
  398. package/src/elements/compare.tsx +0 -111
  399. package/src/elements/compiled.css +0 -2
  400. package/src/elements/composer.tsx +0 -162
  401. package/src/elements/confirm-card.tsx +0 -76
  402. package/src/elements/context-meter.tsx +0 -107
  403. package/src/elements/conversation-item.tsx +0 -120
  404. package/src/elements/conversation-list.tsx +0 -203
  405. package/src/elements/css.ts +0 -5
  406. package/src/elements/default-input.tsx +0 -392
  407. package/src/elements/define-entry.ts +0 -12
  408. package/src/elements/define.tsx +0 -563
  409. package/src/elements/diagnostic-events.ts +0 -114
  410. package/src/elements/dialog.tsx +0 -145
  411. package/src/elements/disclosure.ts +0 -95
  412. package/src/elements/dock.tsx +0 -215
  413. package/src/elements/dropdown.tsx +0 -123
  414. package/src/elements/editable-label.tsx +0 -140
  415. package/src/elements/element-data-types.ts +0 -152
  416. package/src/elements/element-diagnostics.ts +0 -392
  417. package/src/elements/element-manifest.json +0 -354
  418. package/src/elements/element-nonscalar.json +0 -185
  419. package/src/elements/element-types.d.ts +0 -4337
  420. package/src/elements/embed.tsx +0 -35
  421. package/src/elements/empty.tsx +0 -29
  422. package/src/elements/feedback-bar.tsx +0 -66
  423. package/src/elements/file-tree.tsx +0 -62
  424. package/src/elements/file-upload.tsx +0 -44
  425. package/src/elements/form.tsx +0 -94
  426. package/src/elements/hover-card.tsx +0 -80
  427. package/src/elements/icon.tsx +0 -41
  428. package/src/elements/image.tsx +0 -32
  429. package/src/elements/input.tsx +0 -492
  430. package/src/elements/kbd.tsx +0 -45
  431. package/src/elements/link-preview.tsx +0 -34
  432. package/src/elements/loader.tsx +0 -25
  433. package/src/elements/markdown.tsx +0 -38
  434. package/src/elements/menu.tsx +0 -241
  435. package/src/elements/message-skills.tsx +0 -83
  436. package/src/elements/message.tsx +0 -361
  437. package/src/elements/model-switcher.tsx +0 -121
  438. package/src/elements/nav.tsx +0 -87
  439. package/src/elements/notice.tsx +0 -53
  440. package/src/elements/pane-grid.tsx +0 -111
  441. package/src/elements/pane-group.tsx +0 -119
  442. package/src/elements/pane.tsx +0 -129
  443. package/src/elements/popover.tsx +0 -81
  444. package/src/elements/progress-bar.tsx +0 -39
  445. package/src/elements/prompt-dock.tsx +0 -82
  446. package/src/elements/prompt-input.tsx +0 -240
  447. package/src/elements/prompt-suggestions.tsx +0 -113
  448. package/src/elements/radio-group.tsx +0 -129
  449. package/src/elements/reasoning.tsx +0 -71
  450. package/src/elements/register-impl.ts +0 -148
  451. package/src/elements/register.ts +0 -76
  452. package/src/elements/remote.tsx +0 -225
  453. package/src/elements/resizable.globals.d.ts +0 -36
  454. package/src/elements/resizable.tsx +0 -704
  455. package/src/elements/response-stream.tsx +0 -40
  456. package/src/elements/screen.tsx +0 -90
  457. package/src/elements/scroll-area.tsx +0 -33
  458. package/src/elements/scroll-button.tsx +0 -179
  459. package/src/elements/search.tsx +0 -185
  460. package/src/elements/segmented.tsx +0 -129
  461. package/src/elements/select.tsx +0 -165
  462. package/src/elements/separator.tsx +0 -36
  463. package/src/elements/setting-item.tsx +0 -50
  464. package/src/elements/settings-group.tsx +0 -37
  465. package/src/elements/skeleton.tsx +0 -45
  466. package/src/elements/slider.tsx +0 -171
  467. package/src/elements/slot-text.ts +0 -73
  468. package/src/elements/slots.ts +0 -787
  469. package/src/elements/source.tsx +0 -126
  470. package/src/elements/status.tsx +0 -42
  471. package/src/elements/styles.css +0 -328
  472. package/src/elements/switch.tsx +0 -118
  473. package/src/elements/tabs.tsx +0 -95
  474. package/src/elements/tasks.tsx +0 -103
  475. package/src/elements/text-shimmer.tsx +0 -28
  476. package/src/elements/thinking-bar.tsx +0 -43
  477. package/src/elements/thread.tsx +0 -139
  478. package/src/elements/toast.tsx +0 -106
  479. package/src/elements/tool.tsx +0 -78
  480. package/src/elements/tooltip.tsx +0 -85
  481. package/src/elements/validate-messages.ts +0 -76
  482. package/src/elements/voice-input.tsx +0 -100
  483. package/src/elements/voice-output.tsx +0 -82
  484. package/src/index.ts +0 -428
  485. package/src/primitives/audio-bands.ts +0 -174
  486. package/src/primitives/card-component-types.ts +0 -63
  487. package/src/primitives/card-contract.ts +0 -80
  488. package/src/primitives/card-data-types.ts +0 -361
  489. package/src/primitives/card-host.tsx +0 -37
  490. package/src/primitives/card-recovery.ts +0 -160
  491. package/src/primitives/card-registry.tsx +0 -78
  492. package/src/primitives/card-resolution.ts +0 -36
  493. package/src/primitives/card-routing.ts +0 -85
  494. package/src/primitives/card-schemas/artifact.schema.json +0 -92
  495. package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
  496. package/src/primitives/card-schemas/card-event.schema.json +0 -12
  497. package/src/primitives/card-schemas/choice.schema.json +0 -75
  498. package/src/primitives/card-schemas/confirm.schema.json +0 -65
  499. package/src/primitives/card-schemas/embed.schema.json +0 -63
  500. package/src/primitives/card-schemas/form.result.schema.json +0 -7
  501. package/src/primitives/card-schemas/form.schema.json +0 -53
  502. package/src/primitives/card-schemas/link.schema.json +0 -54
  503. package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
  504. package/src/primitives/card-schemas/tasks.schema.json +0 -83
  505. package/src/primitives/card-tags.ts +0 -61
  506. package/src/primitives/card-validate-cards.ts +0 -255
  507. package/src/primitives/card-validate-schemas.ts +0 -58
  508. package/src/primitives/card-validate.ts +0 -131
  509. package/src/primitives/chat-config.tsx +0 -103
  510. package/src/primitives/composer-model.ts +0 -49
  511. package/src/primitives/composer-triggers.ts +0 -35
  512. package/src/primitives/controllable.ts +0 -21
  513. package/src/primitives/create-kai-chat.ts +0 -66
  514. package/src/primitives/create-tween.ts +0 -266
  515. package/src/primitives/embed-providers.ts +0 -254
  516. package/src/primitives/field-mask.ts +0 -256
  517. package/src/primitives/field-semantics.ts +0 -115
  518. package/src/primitives/highlighter.ts +0 -157
  519. package/src/primitives/input-mask.ts +0 -853
  520. package/src/primitives/link-preview.ts +0 -87
  521. package/src/primitives/message-feedback.ts +0 -124
  522. package/src/primitives/pdf-preview.ts +0 -121
  523. package/src/primitives/toast-store.ts +0 -338
  524. package/src/primitives/url-scheme-policy.ts +0 -70
  525. package/src/primitives/use-audio-analysis.ts +0 -340
  526. package/src/primitives/use-auto-resize.ts +0 -31
  527. package/src/primitives/use-resize-observer.ts +0 -45
  528. package/src/primitives/use-sequencer.ts +0 -72
  529. package/src/primitives/use-speech-recognition.ts +0 -146
  530. package/src/primitives/use-stick-to-bottom.ts +0 -75
  531. package/src/primitives/use-text-stream.ts +0 -143
  532. package/src/primitives/use-voice-recorder.ts +0 -62
  533. package/src/primitives/visualizer-sequences.ts +0 -350
  534. package/src/remote/host-embed.ts +0 -345
  535. package/src/remote/index.ts +0 -2
  536. package/src/remote/origin.ts +0 -30
  537. package/src/remote/provider-runtime.ts +0 -262
  538. package/src/remote/provider.ts +0 -2
  539. package/src/remote/validate.ts +0 -22
  540. package/src/remote/version.ts +0 -12
  541. package/src/remote/wire.ts +0 -48
  542. package/src/schemas/from-tool-call.ts +0 -151
  543. package/src/schemas/index.ts +0 -341
  544. package/src/schemas/provider-subsets.ts +0 -538
  545. package/src/schemas/registry.ts +0 -355
  546. package/src/schemas/tool-defs.ts +0 -793
  547. package/src/solid.ts +0 -165
  548. package/src/state/index.ts +0 -44
  549. package/src/state/messages.ts +0 -53
  550. package/src/state/mock.ts +0 -297
  551. package/src/state/parts.ts +0 -295
  552. package/src/state/persistence.ts +0 -180
  553. package/src/state/stream.ts +0 -246
  554. package/src/state/suggestions.ts +0 -9
  555. package/src/state/threads.ts +0 -142
  556. package/src/test-utils/fake-clock.ts +0 -88
  557. package/src/types.ts +0 -53
  558. package/src/ui/action-icons.ts +0 -53
  559. package/src/ui/agent-card.tsx +0 -218
  560. package/src/ui/avatar.tsx +0 -23
  561. package/src/ui/badge.tsx +0 -21
  562. package/src/ui/button.tsx +0 -49
  563. package/src/ui/card.tsx +0 -245
  564. package/src/ui/checkbox-group.tsx +0 -153
  565. package/src/ui/checkbox.tsx +0 -63
  566. package/src/ui/collapsible.tsx +0 -163
  567. package/src/ui/command.tsx +0 -103
  568. package/src/ui/dialog.tsx +0 -223
  569. package/src/ui/dock.tsx +0 -584
  570. package/src/ui/dropdown.tsx +0 -636
  571. package/src/ui/editable-label.tsx +0 -112
  572. package/src/ui/hover-card.tsx +0 -345
  573. package/src/ui/icon.tsx +0 -167
  574. package/src/ui/input.tsx +0 -391
  575. package/src/ui/kbd.tsx +0 -118
  576. package/src/ui/nav.tsx +0 -282
  577. package/src/ui/notice.tsx +0 -84
  578. package/src/ui/overlay.tsx +0 -277
  579. package/src/ui/pane-grid.tsx +0 -117
  580. package/src/ui/pane-group.tsx +0 -291
  581. package/src/ui/pane.tsx +0 -193
  582. package/src/ui/popover.tsx +0 -106
  583. package/src/ui/progress-bar.tsx +0 -83
  584. package/src/ui/prompt-dock.tsx +0 -145
  585. package/src/ui/radio.tsx +0 -150
  586. package/src/ui/resizable.tsx +0 -693
  587. package/src/ui/scroll-area.tsx +0 -26
  588. package/src/ui/segmented.tsx +0 -109
  589. package/src/ui/select.tsx +0 -168
  590. package/src/ui/separator.tsx +0 -10
  591. package/src/ui/settings-group.tsx +0 -67
  592. package/src/ui/skeleton.tsx +0 -73
  593. package/src/ui/slider.tsx +0 -178
  594. package/src/ui/status.tsx +0 -48
  595. package/src/ui/switch.tsx +0 -119
  596. package/src/ui/tabs.tsx +0 -168
  597. package/src/ui/textarea.tsx +0 -21
  598. package/src/ui/tooltip.tsx +0 -118
  599. package/src/utils/cn.ts +0 -30
  600. package/src/wire/chunk.ts +0 -248
  601. package/src/wire/consume.ts +0 -599
  602. package/src/wire/diagnostics.ts +0 -727
  603. package/src/wire/encode-probe.ts +0 -214
  604. package/src/wire/encode.ts +0 -947
  605. package/src/wire/files.ts +0 -342
  606. package/src/wire/formats/anthropic.ts +0 -274
  607. package/src/wire/formats/openai.ts +0 -228
  608. package/src/wire/index.ts +0 -95
  609. package/src/wire/media-types.ts +0 -344
  610. package/src/wire/read.ts +0 -396
  611. package/src/wire/sink-helpers.ts +0 -50
  612. 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
- }