@cueplusplus/ui 0.20.1 → 0.22.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 (236) hide show
  1. package/CHANGELOG.md +133 -0
  2. package/dist/chat/agent-pile.js +2 -2
  3. package/dist/chrome/_status-bar.js +1 -1
  4. package/dist/chrome/app-shell.js +1 -1
  5. package/dist/chrome/navigation-menu.js +3 -3
  6. package/dist/chrome/row.js +1 -1
  7. package/dist/chrome/scroll-area.js +1 -1
  8. package/dist/chrome/section-header.js +1 -1
  9. package/dist/chrome/segmented-control.js +1 -1
  10. package/dist/chrome/tabs.js +1 -1
  11. package/dist/chrome/toolbar.js +1 -1
  12. package/dist/chrome/tree.js +3 -3
  13. package/dist/date/calendar.js +3 -3
  14. package/dist/dmx/channel-matrix.js +1 -1
  15. package/dist/dmx/universe-grid.js +1 -1
  16. package/dist/elements/agent-handoff.js +3 -3
  17. package/dist/elements/agent-plan.js +1 -1
  18. package/dist/elements/agent-status.js +1 -1
  19. package/dist/elements/agent-surface.d.ts +9 -6
  20. package/dist/elements/agent-surface.js +3 -2
  21. package/dist/elements/approval-card.d.ts +29 -3
  22. package/dist/elements/approval-card.js +18 -8
  23. package/dist/elements/artifact-card.js +2 -2
  24. package/dist/elements/canvas-split.js +3 -3
  25. package/dist/elements/chart.js +1 -1
  26. package/dist/elements/chat-panel.js +2 -2
  27. package/dist/elements/checkpoint-history.js +1 -1
  28. package/dist/elements/code-diff.js +1 -1
  29. package/dist/elements/code-runner.js +1 -1
  30. package/dist/elements/composer.d.ts +8 -2
  31. package/dist/elements/composer.js +20 -12
  32. package/dist/elements/computer-use.js +2 -2
  33. package/dist/elements/confidence-marker.js +1 -1
  34. package/dist/elements/connection-state.js +2 -2
  35. package/dist/elements/context-breakdown.js +1 -1
  36. package/dist/elements/context-usage.js +1 -1
  37. package/dist/elements/conversation-search.js +2 -2
  38. package/dist/elements/cost-meter.js +1 -1
  39. package/dist/elements/data-table.js +1 -1
  40. package/dist/elements/diagram.js +1 -1
  41. package/dist/elements/draft-restore.js +2 -2
  42. package/dist/elements/edit-message.js +1 -1
  43. package/dist/elements/elements.css +134 -0
  44. package/dist/elements/elicitation-form.d.ts +8 -1
  45. package/dist/elements/elicitation-form.js +24 -16
  46. package/dist/elements/empty-state.js +3 -3
  47. package/dist/elements/error-state.js +2 -2
  48. package/dist/elements/event-feed.d.ts +88 -0
  49. package/dist/elements/event-feed.js +190 -0
  50. package/dist/elements/feedback-dialog.js +2 -2
  51. package/dist/elements/file-tree.js +1 -1
  52. package/dist/elements/flow-graph.js +2 -2
  53. package/dist/elements/generative.css +13 -0
  54. package/dist/elements/generative.d.ts +8 -6
  55. package/dist/elements/generative.js +4 -3
  56. package/dist/elements/image-generation.js +2 -2
  57. package/dist/elements/index.d.ts +7 -3
  58. package/dist/elements/index.js +5 -2
  59. package/dist/elements/inline-citation.js +1 -1
  60. package/dist/elements/job-progress.js +1 -1
  61. package/dist/elements/launcher-bubble.js +3 -3
  62. package/dist/elements/loading-state.js +1 -1
  63. package/dist/elements/map-answer.js +1 -1
  64. package/dist/elements/math-block.js +1 -1
  65. package/dist/elements/mcp-server-panel.js +3 -3
  66. package/dist/elements/memory-chips.js +1 -1
  67. package/dist/elements/message-attachment.js +3 -3
  68. package/dist/elements/message-branches.js +1 -1
  69. package/dist/elements/message-pair.js +2 -2
  70. package/dist/elements/message-queue.js +1 -1
  71. package/dist/elements/message-timing.js +1 -1
  72. package/dist/elements/mobile-composer.js +1 -1
  73. package/dist/elements/model-picker.js +1 -1
  74. package/dist/elements/number-ticker.js +1 -1
  75. package/dist/elements/onboarding.js +3 -3
  76. package/dist/elements/permission-grant.js +3 -3
  77. package/dist/elements/prompt-library.js +1 -1
  78. package/dist/elements/question-card.d.ts +50 -0
  79. package/dist/elements/question-card.js +117 -0
  80. package/dist/elements/queue-dock.js +1 -1
  81. package/dist/elements/quota-banner.js +1 -1
  82. package/dist/elements/quote-reply.js +3 -3
  83. package/dist/elements/read-aloud.js +2 -2
  84. package/dist/elements/reasoning-effort.js +2 -2
  85. package/dist/elements/reasoning-panel.js +3 -3
  86. package/dist/elements/recommendation-card.js +2 -2
  87. package/dist/elements/regenerate-menu.js +1 -1
  88. package/dist/elements/request-delivery.js +31 -0
  89. package/dist/elements/research-report.js +1 -1
  90. package/dist/elements/retrieval-chunks.js +3 -3
  91. package/dist/elements/revert-dock.js +1 -1
  92. package/dist/elements/reviewable-diff.js +4 -4
  93. package/dist/elements/schedule-card.js +2 -2
  94. package/dist/elements/score-breakdown.js +2 -2
  95. package/dist/elements/scroll-anchor.js +2 -2
  96. package/dist/elements/settings-panel.js +3 -3
  97. package/dist/elements/sources.js +1 -1
  98. package/dist/elements/spec-sheet.js +1 -1
  99. package/dist/elements/stopped-run.js +2 -2
  100. package/dist/elements/streaming-text.js +2 -2
  101. package/dist/elements/subagent-list.js +4 -4
  102. package/dist/elements/suggestions.js +1 -1
  103. package/dist/elements/surfaces.d.ts +6 -6
  104. package/dist/elements/surfaces.js +7 -7
  105. package/dist/elements/tail-status.js +1 -1
  106. package/dist/elements/terminal-block.js +1 -1
  107. package/dist/elements/thinking-indicator.js +1 -1
  108. package/dist/elements/timeline.js +1 -1
  109. package/dist/elements/todo-list.js +1 -1
  110. package/dist/elements/tool-call.d.ts +18 -2
  111. package/dist/elements/tool-call.js +20 -11
  112. package/dist/elements/tool-error.js +2 -2
  113. package/dist/elements/tool-group.d.ts +11 -3
  114. package/dist/elements/tool-group.js +62 -38
  115. package/dist/elements/tool-state.d.ts +13 -0
  116. package/dist/elements/tool-state.js +44 -0
  117. package/dist/elements/tool-timeline.js +2 -2
  118. package/dist/elements/trace-waterfall.js +2 -2
  119. package/dist/elements/unsupported-request-card.d.ts +31 -0
  120. package/dist/elements/unsupported-request-card.js +80 -0
  121. package/dist/elements/vocabulary.d.ts +50 -1
  122. package/dist/elements/vocabulary.js +50 -1
  123. package/dist/elements/voice-conversation.js +5 -5
  124. package/dist/elements/web-preview.js +1 -1
  125. package/dist/elements/web-search.js +2 -2
  126. package/dist/elements/work-collapse.js +1 -1
  127. package/dist/forms/_chassis.d.ts +6 -1
  128. package/dist/forms/_chassis.js +8 -3
  129. package/dist/forms/file-upload.js +1 -1
  130. package/dist/forms/rating.js +1 -1
  131. package/dist/forms/select.js +1 -1
  132. package/dist/forms/switch.js +2 -2
  133. package/dist/forms/toggle.js +1 -1
  134. package/dist/index.d.ts +3 -1
  135. package/dist/index.js +3 -1
  136. package/dist/instruments/_ledger-disclosure.js +1 -1
  137. package/dist/instruments/data-tree.js +1 -1
  138. package/dist/instruments/meter.js +1 -1
  139. package/dist/instruments/seam-grid.js +1 -1
  140. package/dist/layout/_collapse.js +3 -3
  141. package/dist/layout/bento.js +1 -1
  142. package/dist/layout/breadcrumb.js +1 -1
  143. package/dist/layout/carousel.js +1 -1
  144. package/dist/layout/collapsible.js +1 -1
  145. package/dist/layout/index.d.ts +3 -1
  146. package/dist/layout/index.js +3 -1
  147. package/dist/layout/item.js +1 -1
  148. package/dist/layout/link.js +1 -1
  149. package/dist/layout/pagination.js +1 -1
  150. package/dist/layout/pane-seam.d.ts +75 -0
  151. package/dist/layout/pane-seam.js +127 -0
  152. package/dist/layout/resizable.d.ts +2 -1
  153. package/dist/layout/resizable.js +3 -2
  154. package/dist/layout/sidebar.js +3 -3
  155. package/dist/layout/split-pane.d.ts +74 -0
  156. package/dist/layout/split-pane.js +135 -0
  157. package/dist/layout/stepper.js +1 -1
  158. package/dist/lib/auto-grow.js +42 -0
  159. package/dist/overlays/_surface.d.ts +5 -5
  160. package/dist/overlays/_surface.js +4 -4
  161. package/dist/overlays/drawer.js +1 -1
  162. package/dist/overlays/menubar.js +1 -1
  163. package/dist/overlays/sheet.js +1 -1
  164. package/dist/overlays/toast.js +1 -1
  165. package/dist/primitives/button.js +1 -1
  166. package/dist/primitives/chip.d.ts +1 -1
  167. package/dist/styles.css +52 -0
  168. package/dist/system/_paint-stroke-sunken.js +22 -2
  169. package/dist/system/_paint-stroke-surface-1.js +5 -1
  170. package/dist/system/_paint-stroke-surface-2.js +5 -1
  171. package/dist/system/_style-disabled.js +1 -7
  172. package/dist/system/agent-skin.d.ts +11 -5
  173. package/manifest/components/agent-surface.json +5 -4
  174. package/manifest/components/alert-dialog.json +1 -0
  175. package/manifest/components/approval-card.json +45 -7
  176. package/manifest/components/autocomplete.json +2 -0
  177. package/manifest/components/button.json +0 -3
  178. package/manifest/components/card.json +1 -0
  179. package/manifest/components/channel-matrix.json +1 -0
  180. package/manifest/components/chart-tooltip-content.json +1 -0
  181. package/manifest/components/checkbox-group.json +0 -3
  182. package/manifest/components/checkbox.json +0 -3
  183. package/manifest/components/color-field.json +1 -0
  184. package/manifest/components/color-picker.json +1 -0
  185. package/manifest/components/combobox.json +2 -0
  186. package/manifest/components/command-palette.json +1 -0
  187. package/manifest/components/composer-input.json +16 -2
  188. package/manifest/components/composer.json +1 -0
  189. package/manifest/components/context-menu.json +1 -0
  190. package/manifest/components/date-field.json +1 -0
  191. package/manifest/components/date-picker.json +1 -0
  192. package/manifest/components/date-range-picker.json +1 -0
  193. package/manifest/components/dialog.json +1 -0
  194. package/manifest/components/dmx-bar.json +1 -0
  195. package/manifest/components/dmx-strip.json +1 -0
  196. package/manifest/components/drawer.json +1 -0
  197. package/manifest/components/dropdown-menu.json +1 -0
  198. package/manifest/components/elicitation-form.json +16 -1
  199. package/manifest/components/env-var-input.json +1 -0
  200. package/manifest/components/event-feed.json +171 -0
  201. package/manifest/components/event-row.json +116 -0
  202. package/manifest/components/generative-ui.json +4 -3
  203. package/manifest/components/hover-card.json +1 -0
  204. package/manifest/components/input-group.json +1 -0
  205. package/manifest/components/input.json +1 -0
  206. package/manifest/components/menubar.json +1 -0
  207. package/manifest/components/multi-select.json +2 -0
  208. package/manifest/components/musical-time-input.json +1 -0
  209. package/manifest/components/navigation-menu.json +1 -0
  210. package/manifest/components/number-field.json +1 -0
  211. package/manifest/components/otp-field.json +1 -0
  212. package/manifest/components/pane-seam.json +171 -0
  213. package/manifest/components/password-input.json +1 -0
  214. package/manifest/components/popover.json +1 -0
  215. package/manifest/components/question-card.json +157 -0
  216. package/manifest/components/resizable.json +1 -1
  217. package/manifest/components/scrub-input.json +1 -0
  218. package/manifest/components/search-input.json +1 -0
  219. package/manifest/components/select.json +2 -0
  220. package/manifest/components/sheet.json +1 -0
  221. package/manifest/components/split-pane.json +224 -0
  222. package/manifest/components/switch.json +0 -3
  223. package/manifest/components/tags-input.json +2 -0
  224. package/manifest/components/textarea.json +1 -0
  225. package/manifest/components/theme-configurator.json +1 -0
  226. package/manifest/components/time-field.json +1 -0
  227. package/manifest/components/toast.json +1 -0
  228. package/manifest/components/toggle.json +0 -3
  229. package/manifest/components/tool-call.json +46 -2
  230. package/manifest/components/tool-group.json +15 -3
  231. package/manifest/components/tooltip.json +1 -0
  232. package/manifest/components/unsupported-request-card.json +117 -0
  233. package/manifest/fixtures.json +16 -0
  234. package/manifest/manifest.json +134 -56
  235. package/manifest/tokens.json +12 -2
  236. package/package.json +3 -3
@@ -48,8 +48,8 @@ function ScheduleCard({ name, cadence, nextRun, enabled, history, onToggle, clas
48
48
  "aria-checked": enabled,
49
49
  "aria-label": `${enabled ? "Pause" : "Resume"} ${name}`,
50
50
  onClick: onToggle,
51
- className: cn("flex h-5 w-9 shrink-0 items-center rounded-full p-0.5 transition-colors duration-200", enabled ? "bg-accent" : "bg-surface-3"),
52
- children: /* @__PURE__ */ jsx("span", { className: cn("bg-bg size-4 rounded-full transition-transform duration-200 motion-reduce:transition-none", enabled && "translate-x-4") })
51
+ className: cn("flex h-5 w-9 shrink-0 items-center rounded-full p-0.5 transition-colors duration-brisk", enabled ? "bg-accent" : "bg-surface-3"),
52
+ children: /* @__PURE__ */ jsx("span", { className: cn("bg-bg size-4 rounded-full transition-transform duration-brisk motion-reduce:transition-none", enabled && "translate-x-4") })
53
53
  })
54
54
  ]
55
55
  }),
@@ -43,7 +43,7 @@ function ScoreBreakdown({ verdict, total, outOf, criteria, visibleCount, classNa
43
43
  }), /* @__PURE__ */ jsx("div", {
44
44
  className: "flex flex-col gap-2",
45
45
  children: take(criteria, visibleCount).map((criterion) => /* @__PURE__ */ jsxs("div", {
46
- className: "cue-elements-fade-in cue-elements-slide-in-from-bottom-1 cue-elements-animate-in cue-elements-fill-mode-both flex flex-col gap-1 duration-300",
46
+ className: "cue-elements-fade-in cue-elements-slide-in-from-bottom-1 cue-elements-animate-in cue-elements-fill-mode-both flex flex-col gap-1 duration-base",
47
47
  children: [
48
48
  /* @__PURE__ */ jsxs("div", {
49
49
  className: "flex items-baseline gap-2",
@@ -65,7 +65,7 @@ function ScoreBreakdown({ verdict, total, outOf, criteria, visibleCount, classNa
65
65
  /* @__PURE__ */ jsx("span", {
66
66
  className: "bg-surface-2 h-[3px] w-full overflow-hidden rounded-full",
67
67
  children: /* @__PURE__ */ jsx("span", {
68
- className: "block h-full rounded-full bg-stream transition-[width] duration-500 motion-reduce:transition-none",
68
+ className: "block h-full rounded-full bg-stream transition-[width] duration-slow motion-reduce:transition-none",
69
69
  style: { width: `${pct(criterion.score, outOf)}%` }
70
70
  })
71
71
  }),
@@ -100,7 +100,7 @@ function ScrollAnchor({ messages, paused = false, onSettled, className, ...props
100
100
  ref: viewportRef,
101
101
  className: "flex h-full flex-col gap-2.5 overflow-y-hidden scroll-smooth motion-reduce:scroll-auto p-4",
102
102
  children: messages.slice(0, count).map((message, i) => /* @__PURE__ */ jsx("div", {
103
- className: cn("cue-elements-fade-in cue-elements-slide-in-from-bottom-1 cue-elements-animate-in max-w-[85%] text-(length:--cue-text-ui) leading-(--cue-leading-ui) duration-300 motion-reduce:animate-none", message.role === "user" ? cn(field, "self-end rounded-overlay px-3 py-1.5") : "text-fg-muted self-start"),
103
+ className: cn("cue-elements-fade-in cue-elements-slide-in-from-bottom-1 cue-elements-animate-in max-w-[85%] text-(length:--cue-text-ui) leading-(--cue-leading-ui) duration-base motion-reduce:animate-none", message.role === "user" ? cn(field, "self-end rounded-overlay px-3 py-1.5") : "text-fg-muted self-start"),
104
104
  children: message.text
105
105
  }, i))
106
106
  }),
@@ -111,7 +111,7 @@ function ScrollAnchor({ messages, paused = false, onSettled, className, ...props
111
111
  !pinned && newCount > 0 && /* @__PURE__ */ jsxs("button", {
112
112
  type: "button",
113
113
  onClick: jump,
114
- className: cn("bg-surface-2 border border-border-overlay", "cue-elements-fade-in cue-elements-slide-in-from-bottom-2 cue-elements-animate-in absolute inset-x-0 bottom-3 mx-auto flex w-fit items-center gap-1.5 rounded-full px-3.5 py-1.5 text-(length:--cue-text-ui) transition-transform duration-200 hover:-translate-y-px"),
114
+ className: cn("bg-surface-2 border border-border-overlay", "cue-elements-fade-in cue-elements-slide-in-from-bottom-2 cue-elements-animate-in absolute inset-x-0 bottom-3 mx-auto flex w-fit items-center gap-1.5 rounded-full px-3.5 py-1.5 text-(length:--cue-text-ui) transition-transform duration-brisk hover:-translate-y-px"),
115
115
  children: [
116
116
  /* @__PURE__ */ jsx(ArrowDownIcon, { className: "size-3 opacity-60" }),
117
117
  newCount,
@@ -37,7 +37,7 @@ function SettingsPanel({ model, models, systemPrompt, temperature, toggles, onMo
37
37
  type: "button",
38
38
  "aria-pressed": option === model,
39
39
  onClick: () => onModelChange?.(option),
40
- className: cn("flex-1 rounded-full py-1 text-(length:--cue-text-ui) font-medium transition-[background-color,color,scale] duration-150 active:scale-[0.97]", option === model ? "bg-bg text-fg" : "text-fg-muted hover:text-fg-muted"),
40
+ className: cn("flex-1 rounded-full py-1 text-(length:--cue-text-ui) font-medium transition-[background-color,color,scale] duration-fast active:scale-[0.97]", option === model ? "bg-bg text-fg" : "text-fg-muted hover:text-fg-muted"),
41
41
  children: option
42
42
  }, option))
43
43
  })]
@@ -96,8 +96,8 @@ function SettingsPanel({ model, models, systemPrompt, temperature, toggles, onMo
96
96
  "aria-checked": toggle.on,
97
97
  "aria-label": toggle.label,
98
98
  onClick: () => onToggle?.(toggle.key),
99
- className: cn("flex h-5 w-9 shrink-0 items-center rounded-full p-0.5 transition-colors duration-200", toggle.on ? "bg-accent" : "bg-surface-3"),
100
- children: /* @__PURE__ */ jsx("span", { className: cn("bg-bg size-4 rounded-full transition-transform duration-200 motion-reduce:transition-none", toggle.on && "translate-x-4") })
99
+ className: cn("flex h-5 w-9 shrink-0 items-center rounded-full p-0.5 transition-colors duration-brisk", toggle.on ? "bg-accent" : "bg-surface-3"),
100
+ children: /* @__PURE__ */ jsx("span", { className: cn("bg-bg size-4 rounded-full transition-transform duration-brisk motion-reduce:transition-none", toggle.on && "translate-x-4") })
101
101
  })]
102
102
  }, toggle.key))
103
103
  })
@@ -32,7 +32,7 @@ function Sources({ sources, open, onOpenChange, className }) {
32
32
  className: cn(mono, "text-fg-subtle tabular-nums"),
33
33
  children: sources.length
34
34
  }),
35
- /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-3 opacity-60 transition-transform duration-200 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[panel-open]/trigger:rotate-180 motion-reduce:transition-none" })
35
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-3 opacity-60 transition-transform duration-brisk ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[panel-open]/trigger:rotate-180 motion-reduce:transition-none" })
36
36
  ]
37
37
  }), /* @__PURE__ */ jsx(Collapsible.Panel, {
38
38
  className: cn(collapsePanel, "outline-none"),
@@ -29,7 +29,7 @@ function SpecSheet({ title, subtitle, rows, visibleCount, className, ...props })
29
29
  }), /* @__PURE__ */ jsx("div", {
30
30
  className: "flex flex-col",
31
31
  children: take(rows, visibleCount).map((row) => /* @__PURE__ */ jsxs("div", {
32
- className: "border-border cue-elements-fade-in cue-elements-animate-in cue-elements-fill-mode-both flex items-baseline gap-3 border-t py-1.5 duration-300 first:border-t-0 first:pt-0",
32
+ className: "border-border cue-elements-fade-in cue-elements-animate-in cue-elements-fill-mode-both flex items-baseline gap-3 border-t py-1.5 duration-base first:border-t-0 first:pt-0",
33
33
  children: [/* @__PURE__ */ jsx("span", {
34
34
  className: cn(mono, "text-fg-subtle w-24 shrink-0"),
35
35
  children: row.label
@@ -33,13 +33,13 @@ function StoppedRun({ words, reason, onContinue, onDiscard, className, ...props
33
33
  /* @__PURE__ */ jsxs("button", {
34
34
  type: "button",
35
35
  onClick: onContinue,
36
- className: "text-fg-muted hover:bg-surface-2 hover:text-fg ms-auto flex h-7 items-center gap-1 rounded-full px-2.5 text-(length:--cue-text-ui) font-medium transition-[background-color,color,scale] duration-150 active:scale-[0.96]",
36
+ className: "text-fg-muted hover:bg-surface-2 hover:text-fg ms-auto flex h-7 items-center gap-1 rounded-full px-2.5 text-(length:--cue-text-ui) font-medium transition-[background-color,color,scale] duration-fast active:scale-[0.96]",
37
37
  children: ["Continue", /* @__PURE__ */ jsx(ArrowRightIcon, { className: "size-3" })]
38
38
  }),
39
39
  /* @__PURE__ */ jsx("button", {
40
40
  type: "button",
41
41
  onClick: onDiscard,
42
- className: "text-fg-muted hover:bg-surface-2 hover:text-fg flex h-7 items-center rounded-full px-2.5 text-(length:--cue-text-ui) font-medium transition-[background-color,color,scale] duration-150 active:scale-[0.96]",
42
+ className: "text-fg-muted hover:bg-surface-2 hover:text-fg flex h-7 items-center rounded-full px-2.5 text-(length:--cue-text-ui) font-medium transition-[background-color,color,scale] duration-fast active:scale-[0.96]",
43
43
  children: "Discard"
44
44
  })
45
45
  ]
@@ -29,9 +29,9 @@ function StreamingText({ segments, count, streaming, className, ...props }) {
29
29
  children: [shown.map(({ word, mono: isMono }, i) => {
30
30
  const fresh = streaming && shown.length - 1 - i < 2;
31
31
  return /* @__PURE__ */ jsxs("span", {
32
- className: "cue-elements-fade-in cue-elements-animate-in cue-elements-fill-mode-both duration-500 motion-reduce:animate-none",
32
+ className: "cue-elements-fade-in cue-elements-animate-in cue-elements-fill-mode-both duration-slow motion-reduce:animate-none",
33
33
  children: [/* @__PURE__ */ jsx("span", {
34
- className: cn("transition-colors duration-700 motion-reduce:transition-none", fresh && "text-stream", isMono && "bg-surface-2 rounded-control px-1.5 py-0.5 font-mono text-[0.85em]"),
34
+ className: cn("transition-colors duration-slower motion-reduce:transition-none", fresh && "text-stream", isMono && "bg-surface-2 rounded-control px-1.5 py-0.5 font-mono text-[0.85em]"),
35
35
  children: word
36
36
  }), " "]
37
37
  }, i);
@@ -32,7 +32,7 @@ function SubagentList({ agents, completedCount, progress, showSummary, summaryAg
32
32
  children: [/* @__PURE__ */ jsxs("div", {
33
33
  className: "flex items-center gap-2",
34
34
  children: [
35
- done ? /* @__PURE__ */ jsx(CheckIcon, { className: "cue-elements-fade-in cue-elements-zoom-in-90 cue-elements-animate-in size-3.5 shrink-0 text-ok duration-200" }) : /* @__PURE__ */ jsx(Loader2Icon, { className: "text-fg-subtle size-3.5 shrink-0 animate-spin motion-reduce:animate-none" }),
35
+ done ? /* @__PURE__ */ jsx(CheckIcon, { className: "cue-elements-fade-in cue-elements-zoom-in-90 cue-elements-animate-in size-3.5 shrink-0 text-ok duration-brisk" }) : /* @__PURE__ */ jsx(Loader2Icon, { className: "text-fg-subtle size-3.5 shrink-0 animate-spin motion-reduce:animate-none" }),
36
36
  /* @__PURE__ */ jsx("span", {
37
37
  className: "flex-1 truncate text-(length:--cue-text-body)",
38
38
  children: agent.name
@@ -45,13 +45,13 @@ function SubagentList({ agents, completedCount, progress, showSummary, summaryAg
45
45
  }), /* @__PURE__ */ jsx("span", {
46
46
  className: "bg-surface-2 h-[3px] w-full overflow-hidden rounded-full",
47
47
  children: /* @__PURE__ */ jsx("span", {
48
- className: cn("block h-full rounded-full transition-[width] duration-700", done ? "bg-ok/70" : "bg-accent"),
48
+ className: cn("block h-full rounded-full transition-[width] duration-slower", done ? "bg-ok/70" : "bg-accent"),
49
49
  style: { width: `${pct(width, 100)}%` }
50
50
  })
51
51
  })]
52
52
  }, agent.name);
53
53
  }), showSummary && /* @__PURE__ */ jsxs("div", {
54
- className: cn("bg-surface-1 border border-border", "cue-elements-fade-in cue-elements-slide-in-from-bottom-2 cue-elements-animate-in flex flex-col gap-2 rounded-overlay px-3.5 py-2.5 duration-300"),
54
+ className: cn("bg-surface-1 border border-border", "cue-elements-fade-in cue-elements-slide-in-from-bottom-2 cue-elements-animate-in flex flex-col gap-2 rounded-overlay px-3.5 py-2.5 duration-base"),
55
55
  children: [/* @__PURE__ */ jsxs("div", {
56
56
  className: "flex items-center gap-2",
57
57
  children: [
@@ -68,7 +68,7 @@ function SubagentList({ agents, completedCount, progress, showSummary, summaryAg
68
68
  }), /* @__PURE__ */ jsx("span", {
69
69
  className: "bg-surface-2 h-[3px] w-full overflow-hidden rounded-full",
70
70
  children: /* @__PURE__ */ jsx("span", {
71
- className: "bg-accent block h-full rounded-full transition-[width] duration-700",
71
+ className: "bg-accent block h-full rounded-full transition-[width] duration-slower",
72
72
  style: { width: "42%" }
73
73
  })
74
74
  })]
@@ -26,7 +26,7 @@ function Suggestions({ suggestions, selectedSuggestion, cycle, onSuggestion, var
26
26
  type: "button",
27
27
  "aria-pressed": selectedSuggestion === suggestion,
28
28
  onClick: () => onSuggestion(suggestion),
29
- className: cn(paper, "cue-elements-fade-in cue-elements-slide-in-from-bottom-2 cue-elements-animate-in cue-elements-fill-mode-both flex cursor-pointer items-center text-(length:--cue-text-body) transition-transform duration-300 hover:-translate-y-px active:scale-[0.96] motion-reduce:animate-none", list ? "w-full rounded-overlay px-4 py-2.5 text-start" : "rounded-full px-4 py-2", selectedSuggestion === suggestion && "bg-accent text-accent-fg"),
29
+ className: cn(paper, "cue-elements-fade-in cue-elements-slide-in-from-bottom-2 cue-elements-animate-in cue-elements-fill-mode-both flex cursor-pointer items-center text-(length:--cue-text-body) transition-transform duration-base hover:-translate-y-px active:scale-[0.96] motion-reduce:animate-none", list ? "w-full rounded-overlay px-4 py-2.5 text-start" : "rounded-full px-4 py-2", selectedSuggestion === suggestion && "bg-accent text-accent-fg"),
30
30
  style: { animationDelay: `${index * 70}ms` },
31
31
  children: suggestion
32
32
  }, suggestion))
@@ -9,19 +9,19 @@ declare const field = "bg-fg/[0.06]";
9
9
  /** {@link field} for something clickable. */
10
10
  declare const fieldInteractive = "bg-fg/[0.06] transition-colors hover:bg-fg/[0.09]";
11
11
  /** The press affordance: a 4% squash on pointer-down, stilled under reduced motion. */
12
- declare const pressable = "transition-transform duration-150 ease-[cubic-bezier(0.23,1,0.32,1)] active:scale-[0.96] motion-reduce:transition-none";
12
+ declare const pressable = "transition-transform duration-fast ease-[cubic-bezier(0.23,1,0.32,1)] active:scale-[0.96] motion-reduce:transition-none";
13
13
  /** A round chromeless icon button, with the ring cue puts on everything focusable. */
14
- declare const ghostButton = "flex items-center justify-center rounded-full text-fg-muted outline-none transition-[background-color,color,scale] duration-150 hover:bg-surface-2 hover:text-fg active:scale-[0.96] focus-visible:outline-solid focus-visible:outline-[length:var(--cue-style-focus-width,var(--cue-focus-ring))] focus-visible:outline-(--cue-focus) focus-visible:outline-offset-1 motion-reduce:transition-none";
14
+ declare const ghostButton = "flex items-center justify-center rounded-full text-fg-muted outline-none transition-[background-color,color,scale] duration-fast hover:bg-surface-2 hover:text-fg active:scale-[0.96] focus-visible:outline-solid focus-visible:outline-[length:var(--cue-style-focus-width,var(--cue-focus-ring))] focus-visible:outline-(--cue-focus) focus-visible:outline-offset-1 motion-reduce:transition-none";
15
15
  /** The inverse fill: accent ground, accent ink — the one loud button in a panel. */
16
- declare const inkButton = "bg-accent text-accent-fg transition-[background-color,scale] duration-150 ease-[cubic-bezier(0.23,1,0.32,1)] hover:bg-accent-hover active:scale-[0.96] motion-reduce:transition-none";
16
+ declare const inkButton = "bg-accent text-accent-fg transition-[background-color,scale] duration-fast ease-[cubic-bezier(0.23,1,0.32,1)] hover:bg-accent-hover active:scale-[0.96] motion-reduce:transition-none";
17
17
  /** The stacked layer of an icon crossfade. Both layers share one grid cell. */
18
- declare const iconSwap = "[grid-area:1/1] transition-[opacity,scale,filter] duration-200 ease-[cubic-bezier(0.2,0,0,1)] motion-reduce:transition-none";
18
+ declare const iconSwap = "[grid-area:1/1] transition-[opacity,scale,filter] duration-brisk ease-[cubic-bezier(0.2,0,0,1)] motion-reduce:transition-none";
19
19
  /** The icon that is showing. */
20
20
  declare const iconSwapIn = "scale-100 opacity-100 blur-none";
21
21
  /** The icon that is leaving: shrunk, blurred and gone. */
22
22
  declare const iconSwapOut = "scale-[0.25] opacity-0 blur-[4px]";
23
23
  /** The stacked layer of a label crossfade, measured by {@link SwapLabel}. */
24
- declare const labelSwap = "col-start-1 row-start-1 flex w-max items-center gap-1.5 leading-none transition-[opacity,filter] duration-300 ease-[cubic-bezier(0.23,1,0.32,1)] motion-reduce:transition-none";
24
+ declare const labelSwap = "col-start-1 row-start-1 flex w-max items-center gap-1.5 leading-none transition-[opacity,filter] duration-base ease-[cubic-bezier(0.23,1,0.32,1)] motion-reduce:transition-none";
25
25
  /** The label that is showing. */
26
26
  declare const labelSwapIn = "opacity-100 blur-none";
27
27
  /** The label that is leaving, and which must not be selectable while it goes. */
@@ -34,7 +34,7 @@ declare const labelSwapOut = "pointer-events-none select-none opacity-0 blur-[2p
34
34
  * wired to the peer this package already requires rather than to the one
35
35
  * upstream's registry asks for.
36
36
  */
37
- declare const collapsePanel = "h-(--collapsible-panel-height) overflow-hidden transition-[height] duration-200 ease-[cubic-bezier(0.32,0.72,0,1)] data-[ending-style]:h-0 data-[starting-style]:h-0 motion-reduce:transition-none";
37
+ declare const collapsePanel = "h-(--collapsible-panel-height) overflow-hidden transition-[height] duration-brisk ease-[cubic-bezier(0.32,0.72,0,1)] data-[ending-style]:h-0 data-[starting-style]:h-0 motion-reduce:transition-none";
38
38
  /** The streaming hue: what is happening right now, rather than what has happened. */
39
39
  declare const live = "text-stream";
40
40
  /** The metadata typeface: mono, one rung down, tight. Used about a hundred times. */
@@ -13,19 +13,19 @@ const field = "bg-fg/[0.06]";
13
13
  /** {@link field} for something clickable. */
14
14
  const fieldInteractive = "bg-fg/[0.06] transition-colors hover:bg-fg/[0.09]";
15
15
  /** The press affordance: a 4% squash on pointer-down, stilled under reduced motion. */
16
- const pressable = "transition-transform duration-150 ease-[cubic-bezier(0.23,1,0.32,1)] active:scale-[0.96] motion-reduce:transition-none";
16
+ const pressable = "transition-transform duration-fast ease-[cubic-bezier(0.23,1,0.32,1)] active:scale-[0.96] motion-reduce:transition-none";
17
17
  /** A round chromeless icon button, with the ring cue puts on everything focusable. */
18
- const ghostButton = `flex items-center justify-center rounded-full text-fg-muted outline-none transition-[background-color,color,scale] duration-150 hover:bg-surface-2 hover:text-fg active:scale-[0.96] ${FOCUS_RING} motion-reduce:transition-none`;
18
+ const ghostButton = `flex items-center justify-center rounded-full text-fg-muted outline-none transition-[background-color,color,scale] duration-fast hover:bg-surface-2 hover:text-fg active:scale-[0.96] ${FOCUS_RING} motion-reduce:transition-none`;
19
19
  /** The inverse fill: accent ground, accent ink — the one loud button in a panel. */
20
- const inkButton = "bg-accent text-accent-fg transition-[background-color,scale] duration-150 ease-[cubic-bezier(0.23,1,0.32,1)] hover:bg-accent-hover active:scale-[0.96] motion-reduce:transition-none";
20
+ const inkButton = "bg-accent text-accent-fg transition-[background-color,scale] duration-fast ease-[cubic-bezier(0.23,1,0.32,1)] hover:bg-accent-hover active:scale-[0.96] motion-reduce:transition-none";
21
21
  /** The stacked layer of an icon crossfade. Both layers share one grid cell. */
22
- const iconSwap = "[grid-area:1/1] transition-[opacity,scale,filter] duration-200 ease-[cubic-bezier(0.2,0,0,1)] motion-reduce:transition-none";
22
+ const iconSwap = "[grid-area:1/1] transition-[opacity,scale,filter] duration-brisk ease-[cubic-bezier(0.2,0,0,1)] motion-reduce:transition-none";
23
23
  /** The icon that is showing. */
24
24
  const iconSwapIn = "scale-100 opacity-100 blur-none";
25
25
  /** The icon that is leaving: shrunk, blurred and gone. */
26
26
  const iconSwapOut = "scale-[0.25] opacity-0 blur-[4px]";
27
27
  /** The stacked layer of a label crossfade, measured by {@link SwapLabel}. */
28
- const labelSwap = "col-start-1 row-start-1 flex w-max items-center gap-1.5 leading-none transition-[opacity,filter] duration-300 ease-[cubic-bezier(0.23,1,0.32,1)] motion-reduce:transition-none";
28
+ const labelSwap = "col-start-1 row-start-1 flex w-max items-center gap-1.5 leading-none transition-[opacity,filter] duration-base ease-[cubic-bezier(0.23,1,0.32,1)] motion-reduce:transition-none";
29
29
  /** The label that is showing. */
30
30
  const labelSwapIn = "opacity-100 blur-none";
31
31
  /** The label that is leaving, and which must not be selectable while it goes. */
@@ -38,7 +38,7 @@ const labelSwapOut = "pointer-events-none select-none opacity-0 blur-[2px]";
38
38
  * wired to the peer this package already requires rather than to the one
39
39
  * upstream's registry asks for.
40
40
  */
41
- const collapsePanel = "h-(--collapsible-panel-height) overflow-hidden transition-[height] duration-200 ease-[cubic-bezier(0.32,0.72,0,1)] data-[ending-style]:h-0 data-[starting-style]:h-0 motion-reduce:transition-none";
41
+ const collapsePanel = "h-(--collapsible-panel-height) overflow-hidden transition-[height] duration-brisk ease-[cubic-bezier(0.32,0.72,0,1)] data-[ending-style]:h-0 data-[starting-style]:h-0 motion-reduce:transition-none";
42
42
  /** The streaming hue: what is happening right now, rather than what has happened. */
43
43
  const live = "text-stream";
44
44
  /** The metadata typeface: mono, one rung down, tight. Used about a hundred times. */
@@ -96,7 +96,7 @@ function SwapLabel({ active, children, className }) {
96
96
  return /* @__PURE__ */ jsx("span", {
97
97
  "data-slot": "swap-label",
98
98
  style: width === null ? void 0 : { width },
99
- className: cn("grid overflow-x-clip transition-[width] duration-300 ease-[cubic-bezier(0.23,1,0.32,1)] motion-reduce:transition-none", className),
99
+ className: cn("grid overflow-x-clip transition-[width] duration-base ease-[cubic-bezier(0.23,1,0.32,1)] motion-reduce:transition-none", className),
100
100
  children: children.map((layer, index) => /* @__PURE__ */ jsx("span", {
101
101
  ref: index === 0 ? restingRef : activeRef,
102
102
  "aria-hidden": active !== index,
@@ -71,7 +71,7 @@ const TailStatus = React.forwardRef(function TailStatus({ action, detail, active
71
71
  children: active ? /* @__PURE__ */ jsx(Loader2Icon, { className: "size-3.5 animate-spin text-stream motion-reduce:animate-none" }) : null
72
72
  }),
73
73
  /* @__PURE__ */ jsxs("span", {
74
- className: cn("flex min-w-0 flex-1 items-baseline gap-1.5 text-(length:--cue-text-ui)", updatesInPlace && "cue-elements-fade-in cue-elements-animate-in duration-200 motion-reduce:animate-none"),
74
+ className: cn("flex min-w-0 flex-1 items-baseline gap-1.5 text-(length:--cue-text-ui)", updatesInPlace && "cue-elements-fade-in cue-elements-animate-in duration-brisk motion-reduce:animate-none"),
75
75
  children: [/* @__PURE__ */ jsx(ShimmerLabel, {
76
76
  active,
77
77
  className: cn("shrink-0", priority === "attention" ? "text-fg" : "text-fg-muted"),
@@ -40,7 +40,7 @@ function TerminalBlock({ command, lines, visibleCount, done, variant = "paper",
40
40
  children: [take(lines, visibleCount).map((line, i) => {
41
41
  const isLast = i === lines.length - 1;
42
42
  return /* @__PURE__ */ jsx("div", {
43
- className: cn("cue-elements-fade-in cue-elements-animate-in cue-elements-fill-mode-both duration-300", isLast && "text-fg"),
43
+ className: cn("cue-elements-fade-in cue-elements-animate-in cue-elements-fill-mode-both duration-base", isLast && "text-fg"),
44
44
  children: line
45
45
  }, `${i}-${line}`);
46
46
  }), !done && /* @__PURE__ */ jsx("span", {
@@ -22,7 +22,7 @@ function ThinkingIndicator({ label, elapsed, className, ...props }) {
22
22
  className: "size-1.5 shrink-0 animate-pulse rounded-full bg-stream motion-reduce:animate-none"
23
23
  }),
24
24
  /* @__PURE__ */ jsx(ShimmerLabel, {
25
- className: "cue-elements-fade-in cue-elements-slide-in-from-bottom-1 cue-elements-animate-in relative inline-block leading-none duration-300",
25
+ className: "cue-elements-fade-in cue-elements-slide-in-from-bottom-1 cue-elements-animate-in relative inline-block leading-none duration-base",
26
26
  children: label
27
27
  }, label),
28
28
  elapsed !== void 0 && /* @__PURE__ */ jsx("span", {
@@ -18,7 +18,7 @@ function ElementsTimeline({ events, visibleCount, className, ...props }) {
18
18
  className: cn(paper, "flex w-full max-w-sm flex-col rounded-overlay p-4", className),
19
19
  ...props,
20
20
  children: take(events, visibleCount).map((event, i, shown) => /* @__PURE__ */ jsxs("div", {
21
- className: "cue-elements-fade-in cue-elements-slide-in-from-left-1 cue-elements-animate-in cue-elements-fill-mode-both grid grid-cols-[3.5rem_1rem_minmax(0,1fr)] gap-x-2 duration-300",
21
+ className: "cue-elements-fade-in cue-elements-slide-in-from-left-1 cue-elements-animate-in cue-elements-fill-mode-both grid grid-cols-[3.5rem_1rem_minmax(0,1fr)] gap-x-2 duration-base",
22
22
  children: [
23
23
  /* @__PURE__ */ jsx("span", {
24
24
  className: cn(mono, "pt-[3px] text-end tabular-nums", event.when === "future" ? "text-fg-subtle" : "text-fg-subtle"),
@@ -37,7 +37,7 @@ function TodoList({ items, revision, className, ...props }) {
37
37
  }), /* @__PURE__ */ jsx("ul", {
38
38
  className: "flex flex-col gap-1",
39
39
  children: items.map((item) => /* @__PURE__ */ jsxs("li", {
40
- className: "cue-elements-fade-in cue-elements-slide-in-from-bottom-1 cue-elements-animate-in cue-elements-fill-mode-both flex items-start gap-2.5 py-0.5 text-(length:--cue-text-body) duration-300",
40
+ className: "cue-elements-fade-in cue-elements-slide-in-from-bottom-1 cue-elements-animate-in cue-elements-fill-mode-both flex items-start gap-2.5 py-0.5 text-(length:--cue-text-body) duration-base",
41
41
  children: [/* @__PURE__ */ jsx("span", {
42
42
  className: "flex size-4 h-5 shrink-0 items-center justify-center",
43
43
  children: item.status === "done" ? /* @__PURE__ */ jsx("span", {
@@ -1,3 +1,4 @@
1
+ import { ToolAbsence, ToolState } from "./tool-state.js";
1
2
  //#region src/elements/tool-call.d.ts
2
3
  interface ToolCallProps {
3
4
  /** Tool name shown on the collapsed trigger row. */
@@ -11,7 +12,22 @@ interface ToolCallProps {
11
12
  /** Result payload shown once the call is no longer running. */
12
13
  result: string;
13
14
  /** When true a spinner replaces the success check on the trigger. */
14
- running: boolean;
15
+ running?: boolean;
16
+ /**
17
+ * Where the call got to: `running`, `done`, `failed` or `refused`. Each settled
18
+ * state ends the row with its own mark. Supersedes `running`.
19
+ */
20
+ state?: ToolState;
21
+ /**
22
+ * `card` (the default) or `inline`, a denser row that spans its column, for a
23
+ * transcript of many calls.
24
+ */
25
+ variant?: "card" | "inline";
26
+ /**
27
+ * What an empty `result` means: `none` (it returned nothing), `refused` or
28
+ * `unanswered`. Read only when `result` is empty.
29
+ */
30
+ absence?: ToolAbsence;
15
31
  /** Whether the request and result panel is expanded. */
16
32
  open: boolean;
17
33
  /** Called when the user expands or collapses the call. */
@@ -36,6 +52,6 @@ interface ToolCallProps {
36
52
  * onOpenChange={setOpen}
37
53
  * />
38
54
  */
39
- declare function ToolCall({ label, activeLabel, query, request, result, running, open, onOpenChange, className }: ToolCallProps): import("react").JSX.Element;
55
+ declare function ToolCall({ label, activeLabel, query, request, result, running, state, variant, absence, open, onOpenChange, className }: ToolCallProps): import("react").JSX.Element;
40
56
  //#endregion
41
57
  export { ToolCall, ToolCallProps };
@@ -2,9 +2,10 @@
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { FOCUS_RING } from "../system/_focus-ring.js";
4
4
  import { ShimmerLabel, SwapLabel, collapsePanel, field, mono } from "./surfaces.js";
5
+ import { ABSENCE_TEXT, ToolStateMark, resolveToolState } from "./tool-state.js";
5
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
7
  import { Collapsible } from "@base-ui/react/collapsible";
7
- import { CheckIcon, ChevronRightIcon } from "lucide-react";
8
+ import { ChevronRightIcon } from "lucide-react";
8
9
  //#region src/elements/tool-call.tsx
9
10
  /**
10
11
  * One tool invocation with its request and result tucked behind a disclosure.
@@ -23,32 +24,40 @@ import { CheckIcon, ChevronRightIcon } from "lucide-react";
23
24
  * onOpenChange={setOpen}
24
25
  * />
25
26
  */
26
- function ToolCall({ label, activeLabel, query, request, result, running, open, onOpenChange, className }) {
27
+ function ToolCall({ label, activeLabel, query, request, result, running, state, variant = "card", absence, open, onOpenChange, className }) {
28
+ const resolved = resolveToolState(state, running);
29
+ const busy = resolved === "running";
27
30
  return /* @__PURE__ */ jsxs(Collapsible.Root, {
28
31
  "data-slot": "tool-call",
32
+ "data-state": resolved,
33
+ "data-variant": variant,
34
+ "data-inline": variant === "inline" || void 0,
29
35
  open,
30
36
  onOpenChange,
31
- className: cn("w-full max-w-sm", className),
37
+ className: cn("group/tool-call w-full", variant === "card" && "max-w-sm", className),
32
38
  children: [/* @__PURE__ */ jsxs(Collapsible.Trigger, {
33
- className: `group/trigger text-fg-muted hover:text-fg flex items-center gap-2 rounded-control py-1 text-(length:--cue-text-body) transition-colors outline-none ${FOCUS_RING}`,
39
+ className: `group/trigger text-fg-muted hover:text-fg flex items-center gap-2 group-data-inline/tool-call:gap-1.5 group-data-inline/tool-call:py-0.5 group-data-inline/tool-call:text-(length:--cue-text-ui) rounded-control py-1 text-(length:--cue-text-body) transition-colors outline-none ${FOCUS_RING}`,
34
40
  children: [
35
- /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-3.5 shrink-0 opacity-60 transition-transform duration-200 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[panel-open]/trigger:rotate-90 motion-reduce:transition-none" }),
41
+ /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-3.5 shrink-0 opacity-60 transition-transform duration-brisk ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[panel-open]/trigger:rotate-90 motion-reduce:transition-none" }),
36
42
  /* @__PURE__ */ jsxs(SwapLabel, {
37
- active: running ? 0 : 1,
43
+ active: busy ? 0 : 1,
38
44
  className: "text-start",
39
45
  children: [/* @__PURE__ */ jsx(ShimmerLabel, {
40
- active: running,
46
+ active: busy,
41
47
  className: "relative inline-block leading-none",
42
48
  children: activeLabel
43
49
  }), /* @__PURE__ */ jsx(Fragment, { children: label })]
44
50
  }),
45
51
  /* @__PURE__ */ jsx("span", {
46
- className: cn(mono, "bg-surface-2 text-fg-muted rounded-control px-1.5 py-0.5"),
52
+ className: cn(mono, "bg-surface-2 text-fg-muted rounded-control px-1.5 py-0.5 group-data-inline/tool-call:bg-transparent group-data-inline/tool-call:px-0"),
47
53
  children: query
48
54
  }),
49
55
  /* @__PURE__ */ jsx("span", {
50
56
  className: "ms-auto flex w-4 items-center justify-end",
51
- children: !running && /* @__PURE__ */ jsx(CheckIcon, { className: "cue-elements-fade-in cue-elements-zoom-in-90 cue-elements-animate-in size-3.5 text-ok duration-200" })
57
+ children: /* @__PURE__ */ jsx(ToolStateMark, {
58
+ state: resolved,
59
+ className: "size-3.5"
60
+ })
52
61
  })
53
62
  ]
54
63
  }), /* @__PURE__ */ jsx(Collapsible.Panel, {
@@ -73,8 +82,8 @@ function ToolCall({ label, activeLabel, query, request, result, running, open, o
73
82
  className: cn(mono, "text-fg-subtle mb-1"),
74
83
  children: "Result"
75
84
  }), /* @__PURE__ */ jsx("p", {
76
- className: "text-fg",
77
- children: result
85
+ className: result === "" && absence !== void 0 ? "text-fg-muted italic" : "text-fg",
86
+ children: result === "" && absence !== void 0 ? ABSENCE_TEXT[absence] : result
78
87
  })]
79
88
  })
80
89
  ]
@@ -59,13 +59,13 @@ function ToolError({ name, target, message, attempt, maxAttempts, retrying, onRe
59
59
  type: "button",
60
60
  onClick: onSkip,
61
61
  disabled: !onSkip,
62
- className: "text-fg-muted hover:bg-surface-2 hover:text-fg h-7 rounded-full px-2.5 text-(length:--cue-text-ui) font-medium transition-[background-color,color,scale] duration-150 active:scale-[0.96] disabled:pointer-events-none disabled:opacity-30",
62
+ className: "text-fg-muted hover:bg-surface-2 hover:text-fg h-7 rounded-full px-2.5 text-(length:--cue-text-ui) font-medium transition-[background-color,color,scale] duration-fast active:scale-[0.96] disabled:pointer-events-none disabled:opacity-30",
63
63
  children: "Skip"
64
64
  }), /* @__PURE__ */ jsxs("button", {
65
65
  type: "button",
66
66
  onClick: onRetry,
67
67
  disabled: retrying,
68
- className: "text-fg-muted hover:bg-surface-2 hover:text-fg flex h-7 items-center gap-1.5 rounded-full px-2.5 text-(length:--cue-text-ui) font-medium transition-[background-color,color,scale] duration-150 active:scale-[0.96] disabled:pointer-events-none",
68
+ className: "text-fg-muted hover:bg-surface-2 hover:text-fg flex h-7 items-center gap-1.5 rounded-full px-2.5 text-(length:--cue-text-ui) font-medium transition-[background-color,color,scale] duration-fast active:scale-[0.96] disabled:pointer-events-none",
69
69
  children: [retrying ? /* @__PURE__ */ jsx(Loader2Icon, { className: "size-3 animate-spin motion-reduce:animate-none" }) : /* @__PURE__ */ jsx(RotateCwIcon, { className: "size-3" }), retrying ? "Retrying" : "Retry"]
70
70
  })]
71
71
  })
@@ -1,7 +1,10 @@
1
1
  import { ComponentProps } from "react";
2
2
  //#region src/elements/tool-group.d.ts
3
- /** Where one tool in a group got to: still running, finished, or failed. */
4
- type GroupedToolState = "running" | "done" | "failed";
3
+ /**
4
+ * Where one tool in a group got to: still running, finished, failed, or refused before
5
+ * it ran.
6
+ */
7
+ type GroupedToolState = "running" | "done" | "failed" | "refused";
5
8
  /** One row of a tool group: what ran, against what, and how it ended. */
6
9
  interface GroupedTool {
7
10
  /** Stable identity for the row key. */
@@ -28,7 +31,7 @@ interface GroupedTool {
28
31
  * onOpenChange={setOpen}
29
32
  * />
30
33
  */
31
- declare function ToolGroup({ label, tools, open, onOpenChange, className, ...props }: Omit<ComponentProps<"div">, "children" | "label" | "tools" | "open" | "onOpenChange"> & {
34
+ declare function ToolGroup({ label, tools, open, onOpenChange, variant, className, ...props }: Omit<ComponentProps<"div">, "children" | "label" | "tools" | "open" | "onOpenChange"> & {
32
35
  /** What the group did, as one line. */
33
36
  label: string;
34
37
  /**
@@ -40,6 +43,11 @@ declare function ToolGroup({ label, tools, open, onOpenChange, className, ...pro
40
43
  open: boolean;
41
44
  /** Called when the group is expanded or collapsed. */
42
45
  onOpenChange?: (open: boolean) => void;
46
+ /**
47
+ * `card` (the default) or `inline`, a row in its column without the paper, for a
48
+ * transcript of many groups.
49
+ */
50
+ variant?: "card" | "inline";
43
51
  }): import("react").JSX.Element;
44
52
  //#endregion
45
53
  export { GroupedTool, GroupedToolState, ToolGroup };
@@ -1,8 +1,9 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
- import { mono, paper } from "./surfaces.js";
3
+ import { mono } from "./surfaces.js";
4
+ import { ToolStateMark } from "./tool-state.js";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
- import { CheckIcon, ChevronRightIcon, Loader2Icon, XIcon } from "lucide-react";
6
+ import { ChevronRightIcon, Loader2Icon } from "lucide-react";
6
7
  //#region src/elements/tool-group.tsx
7
8
  /**
8
9
  * Calls that went out together, collapsed to one row until you want the detail.
@@ -17,54 +18,77 @@ import { CheckIcon, ChevronRightIcon, Loader2Icon, XIcon } from "lucide-react";
17
18
  * onOpenChange={setOpen}
18
19
  * />
19
20
  */
20
- function ToolGroup({ label, tools, open, onOpenChange, className, ...props }) {
21
+ function ToolGroup({ label, tools, open, onOpenChange, variant = "card", className, ...props }) {
21
22
  const running = tools.filter((tool) => tool.state === "running").length;
22
23
  const failed = tools.filter((tool) => tool.state === "failed").length;
24
+ const refused = tools.filter((tool) => tool.state === "refused").length;
25
+ const live = open ? void 0 : tools.find((tool) => tool.state === "running");
23
26
  return /* @__PURE__ */ jsxs("div", {
24
27
  "data-slot": "tool-group",
25
- className: cn(paper, "flex w-full max-w-sm flex-col overflow-hidden rounded-overlay", className),
28
+ "data-variant": variant,
29
+ className: cn(variant === "card" && "bg-surface-1 border border-border", "flex w-full flex-col overflow-hidden", variant === "card" && "max-w-sm rounded-overlay", className),
26
30
  ...props,
27
- children: [/* @__PURE__ */ jsxs("button", {
28
- type: "button",
29
- "aria-expanded": open,
30
- onClick: () => onOpenChange?.(!open),
31
- className: "hover:bg-surface-1 flex items-center gap-2.5 px-3.5 py-2.5 text-start transition-colors",
32
- children: [
33
- /* @__PURE__ */ jsx(ChevronRightIcon, { className: cn("text-fg-subtle size-3 shrink-0 transition-transform duration-200 motion-reduce:transition-none", open && "rotate-90") }),
34
- /* @__PURE__ */ jsx("span", {
35
- className: "min-w-0 flex-1 truncate text-(length:--cue-text-body)",
36
- children: label
37
- }),
38
- /* @__PURE__ */ jsx("span", {
39
- className: cn(mono, "text-fg-subtle shrink-0 tabular-nums"),
40
- children: running > 0 ? `${tools.length - running}/${tools.length}` : failed > 0 ? `${failed} failed` : `${tools.length} done`
41
- }),
42
- running > 0 ? /* @__PURE__ */ jsx(Loader2Icon, { className: "text-fg-subtle size-3.5 shrink-0 animate-spin motion-reduce:animate-none" }) : failed > 0 ? /* @__PURE__ */ jsx(XIcon, { className: "size-3.5 shrink-0 text-danger" }) : /* @__PURE__ */ jsx(CheckIcon, { className: "size-3.5 shrink-0 text-ok" })
43
- ]
44
- }), open && /* @__PURE__ */ jsx("div", {
45
- className: "border-border cue-elements-fade-in cue-elements-slide-in-from-top-1 cue-elements-animate-in flex flex-col border-t duration-200",
46
- children: tools.map((tool) => /* @__PURE__ */ jsxs("div", {
47
- className: "flex items-center gap-2.5 px-3.5 py-2",
31
+ children: [
32
+ /* @__PURE__ */ jsxs("button", {
33
+ type: "button",
34
+ "aria-expanded": open,
35
+ onClick: () => onOpenChange?.(!open),
36
+ className: "hover:bg-surface-1 flex items-center gap-2.5 px-3.5 py-2.5 text-start transition-colors",
48
37
  children: [
38
+ /* @__PURE__ */ jsx(ChevronRightIcon, { className: cn("text-fg-subtle size-3 shrink-0 transition-transform duration-brisk motion-reduce:transition-none", open && "rotate-90") }),
49
39
  /* @__PURE__ */ jsx("span", {
50
- className: "flex size-3.5 shrink-0 items-center justify-center",
51
- children: tool.state === "running" ? /* @__PURE__ */ jsx(Loader2Icon, { className: "text-fg-subtle size-3 animate-spin motion-reduce:animate-none" }) : tool.state === "failed" ? /* @__PURE__ */ jsx(XIcon, { className: "size-3 text-danger" }) : /* @__PURE__ */ jsx(CheckIcon, { className: "size-3 text-ok" })
40
+ className: "min-w-0 flex-1 truncate text-(length:--cue-text-body)",
41
+ children: label
52
42
  }),
53
43
  /* @__PURE__ */ jsx("span", {
54
- className: cn("font-mono text-(length:--cue-text-label) tracking-tight", "text-fg-muted shrink-0"),
55
- children: tool.name
44
+ className: cn(mono, "text-fg-subtle shrink-0 tabular-nums"),
45
+ children: running > 0 ? `${tools.length - running}/${tools.length}` : failed > 0 ? `${failed} failed` : refused > 0 ? `${refused} refused` : `${tools.length} done`
56
46
  }),
57
- /* @__PURE__ */ jsx("span", {
58
- className: "text-fg-muted min-w-0 flex-1 truncate text-(length:--cue-text-body)",
59
- children: tool.target
60
- }),
61
- tool.durationMs !== void 0 && /* @__PURE__ */ jsxs("span", {
62
- className: cn("font-mono text-(length:--cue-text-label) tracking-tight", "text-fg-subtle shrink-0 tabular-nums"),
63
- children: [tool.durationMs, "ms"]
47
+ running > 0 ? /* @__PURE__ */ jsx(Loader2Icon, { className: "text-fg-subtle size-3.5 shrink-0 animate-spin motion-reduce:animate-none" }) : /* @__PURE__ */ jsx(ToolStateMark, {
48
+ state: failed > 0 ? "failed" : refused > 0 ? "refused" : "done",
49
+ animated: false,
50
+ className: "size-3.5 shrink-0"
64
51
  })
65
52
  ]
66
- }, tool.id))
67
- })]
53
+ }),
54
+ live !== void 0 && /* @__PURE__ */ jsxs("p", {
55
+ "data-slot": "tool-group-live",
56
+ className: cn("font-mono text-(length:--cue-text-label) tracking-tight", "text-fg-subtle -mt-1.5 truncate px-3.5 pb-2 ps-9"),
57
+ children: [
58
+ live.name,
59
+ " ",
60
+ live.target
61
+ ]
62
+ }),
63
+ open && /* @__PURE__ */ jsx("div", {
64
+ className: "border-border cue-elements-fade-in cue-elements-slide-in-from-top-1 cue-elements-animate-in flex flex-col border-t duration-brisk",
65
+ children: tools.map((tool) => /* @__PURE__ */ jsxs("div", {
66
+ className: "flex items-center gap-2.5 px-3.5 py-2",
67
+ children: [
68
+ /* @__PURE__ */ jsx("span", {
69
+ className: "flex size-3.5 shrink-0 items-center justify-center",
70
+ children: tool.state === "running" ? /* @__PURE__ */ jsx(Loader2Icon, { className: "text-fg-subtle size-3 animate-spin motion-reduce:animate-none" }) : /* @__PURE__ */ jsx(ToolStateMark, {
71
+ state: tool.state,
72
+ animated: false,
73
+ className: "size-3"
74
+ })
75
+ }),
76
+ /* @__PURE__ */ jsx("span", {
77
+ className: cn("font-mono text-(length:--cue-text-label) tracking-tight", "text-fg-muted shrink-0"),
78
+ children: tool.name
79
+ }),
80
+ /* @__PURE__ */ jsx("span", {
81
+ className: "text-fg-muted min-w-0 flex-1 truncate text-(length:--cue-text-body)",
82
+ children: tool.target
83
+ }),
84
+ tool.durationMs !== void 0 && /* @__PURE__ */ jsxs("span", {
85
+ className: cn("font-mono text-(length:--cue-text-label) tracking-tight", "text-fg-subtle shrink-0 tabular-nums"),
86
+ children: [tool.durationMs, "ms"]
87
+ })
88
+ ]
89
+ }, tool.id))
90
+ })
91
+ ]
68
92
  });
69
93
  }
70
94
  //#endregion
@@ -0,0 +1,13 @@
1
+ //#region src/elements/tool-state.d.ts
2
+ /**
3
+ * Where a tool call got to: still running, finished, failed, or refused before
4
+ * it ran (cue-ui-51). The four a transcript has to tell apart at a glance.
5
+ */
6
+ type ToolState = "running" | "done" | "failed" | "refused";
7
+ /**
8
+ * What kind of nothing an empty result is (cue-ui-52): the call ran and
9
+ * returned nothing, it was refused, or it was never answered.
10
+ */
11
+ type ToolAbsence = "none" | "refused" | "unanswered";
12
+ //#endregion
13
+ export { ToolAbsence, ToolState };