@adea-ai/ui 0.140.0 → 0.142.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 (455) hide show
  1. package/dist/components/composites/appearance-editor/appearance-editor.js +2 -2
  2. package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
  3. package/dist/components/composites/catalog-browser/catalog-browser-group.js +1 -1
  4. package/dist/components/composites/chain-of-thought/chain-of-thought.d.ts +56 -0
  5. package/dist/components/composites/chain-of-thought/chain-of-thought.d.ts.map +1 -0
  6. package/dist/components/composites/chain-of-thought/chain-of-thought.js +117 -0
  7. package/dist/components/composites/chain-of-thought/chain-of-thought.js.map +1 -0
  8. package/dist/components/composites/chain-of-thought/index.d.ts +2 -0
  9. package/dist/components/composites/chain-of-thought/index.d.ts.map +1 -0
  10. package/dist/components/composites/chain-of-thought/index.js +2 -0
  11. package/dist/components/composites/chat/chat.d.ts +67 -0
  12. package/dist/components/composites/chat/chat.d.ts.map +1 -0
  13. package/dist/components/composites/chat/chat.js +179 -0
  14. package/dist/components/composites/chat/chat.js.map +1 -0
  15. package/dist/components/composites/chat/index.d.ts +2 -0
  16. package/dist/components/composites/chat/index.d.ts.map +1 -0
  17. package/dist/components/composites/chat/index.js +2 -0
  18. package/dist/components/composites/checkpoint/checkpoint-model.d.ts +34 -0
  19. package/dist/components/composites/checkpoint/checkpoint-model.d.ts.map +1 -0
  20. package/dist/components/composites/checkpoint/checkpoint-model.js +48 -0
  21. package/dist/components/composites/checkpoint/checkpoint-model.js.map +1 -0
  22. package/dist/components/composites/checkpoint/checkpoint.d.ts +48 -0
  23. package/dist/components/composites/checkpoint/checkpoint.d.ts.map +1 -0
  24. package/dist/components/composites/checkpoint/checkpoint.js +160 -0
  25. package/dist/components/composites/checkpoint/checkpoint.js.map +1 -0
  26. package/dist/components/composites/checkpoint/index.d.ts +3 -0
  27. package/dist/components/composites/checkpoint/index.d.ts.map +1 -0
  28. package/dist/components/composites/checkpoint/index.js +3 -0
  29. package/dist/components/composites/confirmation/confirmation-model.d.ts +45 -0
  30. package/dist/components/composites/confirmation/confirmation-model.d.ts.map +1 -0
  31. package/dist/components/composites/confirmation/confirmation-model.js +51 -0
  32. package/dist/components/composites/confirmation/confirmation-model.js.map +1 -0
  33. package/dist/components/composites/confirmation/confirmation.d.ts +72 -0
  34. package/dist/components/composites/confirmation/confirmation.d.ts.map +1 -0
  35. package/dist/components/composites/confirmation/confirmation.js +300 -0
  36. package/dist/components/composites/confirmation/confirmation.js.map +1 -0
  37. package/dist/components/composites/confirmation/index.d.ts +3 -0
  38. package/dist/components/composites/confirmation/index.d.ts.map +1 -0
  39. package/dist/components/composites/confirmation/index.js +3 -0
  40. package/dist/components/composites/context/context-model.d.ts +69 -0
  41. package/dist/components/composites/context/context-model.d.ts.map +1 -0
  42. package/dist/components/composites/context/context-model.js +122 -0
  43. package/dist/components/composites/context/context-model.js.map +1 -0
  44. package/dist/components/composites/context/context.d.ts +38 -0
  45. package/dist/components/composites/context/context.d.ts.map +1 -0
  46. package/dist/components/composites/context/context.js +234 -0
  47. package/dist/components/composites/context/context.js.map +1 -0
  48. package/dist/components/composites/context/index.d.ts +3 -0
  49. package/dist/components/composites/context/index.d.ts.map +1 -0
  50. package/dist/components/composites/context/index.js +3 -0
  51. package/dist/components/composites/file-tree/build-file-tree.d.ts +138 -0
  52. package/dist/components/composites/file-tree/build-file-tree.d.ts.map +1 -0
  53. package/dist/components/composites/file-tree/build-file-tree.js +325 -0
  54. package/dist/components/composites/file-tree/build-file-tree.js.map +1 -0
  55. package/dist/components/composites/file-tree/file-tree.d.ts +74 -0
  56. package/dist/components/composites/file-tree/file-tree.d.ts.map +1 -0
  57. package/dist/components/composites/file-tree/file-tree.js +389 -0
  58. package/dist/components/composites/file-tree/file-tree.js.map +1 -0
  59. package/dist/components/composites/file-tree/index.d.ts +3 -0
  60. package/dist/components/composites/file-tree/index.d.ts.map +1 -0
  61. package/dist/components/composites/file-tree/index.js +3 -0
  62. package/dist/components/composites/inline-citation/citation.d.ts +37 -0
  63. package/dist/components/composites/inline-citation/citation.d.ts.map +1 -0
  64. package/dist/components/composites/inline-citation/citation.js +52 -0
  65. package/dist/components/composites/inline-citation/citation.js.map +1 -0
  66. package/dist/components/composites/inline-citation/index.d.ts +3 -0
  67. package/dist/components/composites/inline-citation/index.d.ts.map +1 -0
  68. package/dist/components/composites/inline-citation/index.js +3 -0
  69. package/dist/components/composites/inline-citation/inline-citation.d.ts +64 -0
  70. package/dist/components/composites/inline-citation/inline-citation.d.ts.map +1 -0
  71. package/dist/components/composites/inline-citation/inline-citation.js +272 -0
  72. package/dist/components/composites/inline-citation/inline-citation.js.map +1 -0
  73. package/dist/components/composites/message-scroller/index.d.ts +3 -0
  74. package/dist/components/composites/message-scroller/index.d.ts.map +1 -0
  75. package/dist/components/composites/message-scroller/index.js +3 -0
  76. package/dist/components/composites/message-scroller/message-scroller.d.ts +55 -0
  77. package/dist/components/composites/message-scroller/message-scroller.d.ts.map +1 -0
  78. package/dist/components/composites/message-scroller/message-scroller.js +201 -0
  79. package/dist/components/composites/message-scroller/message-scroller.js.map +1 -0
  80. package/dist/components/composites/message-scroller/scroll-anchor.d.ts +66 -0
  81. package/dist/components/composites/message-scroller/scroll-anchor.d.ts.map +1 -0
  82. package/dist/components/composites/message-scroller/scroll-anchor.js +122 -0
  83. package/dist/components/composites/message-scroller/scroll-anchor.js.map +1 -0
  84. package/dist/components/composites/model-selector/index.d.ts +3 -0
  85. package/dist/components/composites/model-selector/index.d.ts.map +1 -0
  86. package/dist/components/composites/model-selector/index.js +3 -0
  87. package/dist/components/composites/model-selector/model-selector.d.ts +55 -0
  88. package/dist/components/composites/model-selector/model-selector.d.ts.map +1 -0
  89. package/dist/components/composites/model-selector/model-selector.js +490 -0
  90. package/dist/components/composites/model-selector/model-selector.js.map +1 -0
  91. package/dist/components/composites/model-selector/models.d.ts +51 -0
  92. package/dist/components/composites/model-selector/models.d.ts.map +1 -0
  93. package/dist/components/composites/model-selector/models.js +71 -0
  94. package/dist/components/composites/model-selector/models.js.map +1 -0
  95. package/dist/components/composites/plan/index.d.ts +2 -0
  96. package/dist/components/composites/plan/index.d.ts.map +1 -0
  97. package/dist/components/composites/plan/index.js +2 -0
  98. package/dist/components/composites/plan/plan.d.ts +61 -0
  99. package/dist/components/composites/plan/plan.d.ts.map +1 -0
  100. package/dist/components/composites/plan/plan.js +130 -0
  101. package/dist/components/composites/plan/plan.js.map +1 -0
  102. package/dist/components/composites/queue/index.d.ts +2 -0
  103. package/dist/components/composites/queue/index.d.ts.map +1 -0
  104. package/dist/components/composites/queue/index.js +2 -0
  105. package/dist/components/composites/queue/queue.d.ts +77 -0
  106. package/dist/components/composites/queue/queue.d.ts.map +1 -0
  107. package/dist/components/composites/queue/queue.js +271 -0
  108. package/dist/components/composites/queue/queue.js.map +1 -0
  109. package/dist/components/composites/reasoning/index.d.ts +2 -0
  110. package/dist/components/composites/reasoning/index.d.ts.map +1 -0
  111. package/dist/components/composites/reasoning/index.js +2 -0
  112. package/dist/components/composites/reasoning/reasoning.d.ts +62 -0
  113. package/dist/components/composites/reasoning/reasoning.d.ts.map +1 -0
  114. package/dist/components/composites/reasoning/reasoning.js +156 -0
  115. package/dist/components/composites/reasoning/reasoning.js.map +1 -0
  116. package/dist/components/composites/sources/index.d.ts +3 -0
  117. package/dist/components/composites/sources/index.d.ts.map +1 -0
  118. package/dist/components/composites/sources/index.js +3 -0
  119. package/dist/components/composites/sources/source.d.ts +46 -0
  120. package/dist/components/composites/sources/source.d.ts.map +1 -0
  121. package/dist/components/composites/sources/source.js +74 -0
  122. package/dist/components/composites/sources/source.js.map +1 -0
  123. package/dist/components/composites/sources/sources.d.ts +45 -0
  124. package/dist/components/composites/sources/sources.d.ts.map +1 -0
  125. package/dist/components/composites/sources/sources.js +175 -0
  126. package/dist/components/composites/sources/sources.js.map +1 -0
  127. package/dist/components/composites/stack-trace/index.d.ts +3 -0
  128. package/dist/components/composites/stack-trace/index.d.ts.map +1 -0
  129. package/dist/components/composites/stack-trace/index.js +3 -0
  130. package/dist/components/composites/stack-trace/parse-stack-trace.d.ts +118 -0
  131. package/dist/components/composites/stack-trace/parse-stack-trace.d.ts.map +1 -0
  132. package/dist/components/composites/stack-trace/parse-stack-trace.js +376 -0
  133. package/dist/components/composites/stack-trace/parse-stack-trace.js.map +1 -0
  134. package/dist/components/composites/stack-trace/stack-trace.d.ts +63 -0
  135. package/dist/components/composites/stack-trace/stack-trace.d.ts.map +1 -0
  136. package/dist/components/composites/stack-trace/stack-trace.js +491 -0
  137. package/dist/components/composites/stack-trace/stack-trace.js.map +1 -0
  138. package/dist/components/composites/subagent/index.d.ts +2 -0
  139. package/dist/components/composites/subagent/index.d.ts.map +1 -0
  140. package/dist/components/composites/subagent/index.js +2 -0
  141. package/dist/components/composites/subagent/subagent.d.ts +55 -0
  142. package/dist/components/composites/subagent/subagent.d.ts.map +1 -0
  143. package/dist/components/composites/subagent/subagent.js +138 -0
  144. package/dist/components/composites/subagent/subagent.js.map +1 -0
  145. package/dist/components/composites/suggestion/index.d.ts +2 -0
  146. package/dist/components/composites/suggestion/index.d.ts.map +1 -0
  147. package/dist/components/composites/suggestion/index.js +2 -0
  148. package/dist/components/composites/suggestion/suggestion.d.ts +37 -0
  149. package/dist/components/composites/suggestion/suggestion.d.ts.map +1 -0
  150. package/dist/components/composites/suggestion/suggestion.js +100 -0
  151. package/dist/components/composites/suggestion/suggestion.js.map +1 -0
  152. package/dist/components/composites/task/index.d.ts +2 -0
  153. package/dist/components/composites/task/index.d.ts.map +1 -0
  154. package/dist/components/composites/task/index.js +2 -0
  155. package/dist/components/composites/task/task.d.ts +96 -0
  156. package/dist/components/composites/task/task.d.ts.map +1 -0
  157. package/dist/components/composites/task/task.js +311 -0
  158. package/dist/components/composites/task/task.js.map +1 -0
  159. package/dist/components/composites/terminal/ansi.d.ts +101 -0
  160. package/dist/components/composites/terminal/ansi.d.ts.map +1 -0
  161. package/dist/components/composites/terminal/ansi.js +544 -0
  162. package/dist/components/composites/terminal/ansi.js.map +1 -0
  163. package/dist/components/composites/terminal/index.d.ts +4 -0
  164. package/dist/components/composites/terminal/index.d.ts.map +1 -0
  165. package/dist/components/composites/terminal/index.js +4 -0
  166. package/dist/components/composites/terminal/terminal-model.d.ts +63 -0
  167. package/dist/components/composites/terminal/terminal-model.d.ts.map +1 -0
  168. package/dist/components/composites/terminal/terminal-model.js +69 -0
  169. package/dist/components/composites/terminal/terminal-model.js.map +1 -0
  170. package/dist/components/composites/terminal/terminal.d.ts +88 -0
  171. package/dist/components/composites/terminal/terminal.d.ts.map +1 -0
  172. package/dist/components/composites/terminal/terminal.js +500 -0
  173. package/dist/components/composites/terminal/terminal.js.map +1 -0
  174. package/dist/components/composites/test-results/index.d.ts +3 -0
  175. package/dist/components/composites/test-results/index.d.ts.map +1 -0
  176. package/dist/components/composites/test-results/index.js +3 -0
  177. package/dist/components/composites/test-results/test-results-model.d.ts +154 -0
  178. package/dist/components/composites/test-results/test-results-model.d.ts.map +1 -0
  179. package/dist/components/composites/test-results/test-results-model.js +252 -0
  180. package/dist/components/composites/test-results/test-results-model.js.map +1 -0
  181. package/dist/components/composites/test-results/test-results.d.ts +60 -0
  182. package/dist/components/composites/test-results/test-results.d.ts.map +1 -0
  183. package/dist/components/composites/test-results/test-results.js +631 -0
  184. package/dist/components/composites/test-results/test-results.js.map +1 -0
  185. package/dist/components/composites/tool/format-tool-value.d.ts +37 -0
  186. package/dist/components/composites/tool/format-tool-value.d.ts.map +1 -0
  187. package/dist/components/composites/tool/format-tool-value.js +135 -0
  188. package/dist/components/composites/tool/format-tool-value.js.map +1 -0
  189. package/dist/components/composites/tool/index.d.ts +3 -0
  190. package/dist/components/composites/tool/index.d.ts.map +1 -0
  191. package/dist/components/composites/tool/index.js +3 -0
  192. package/dist/components/composites/tool/tool.d.ts +69 -0
  193. package/dist/components/composites/tool/tool.d.ts.map +1 -0
  194. package/dist/components/composites/tool/tool.js +214 -0
  195. package/dist/components/composites/tool/tool.js.map +1 -0
  196. package/dist/components/composites/update-dialog/update-dialog.js +1 -1
  197. package/dist/components/conversation/conversation-surface.d.ts +7 -0
  198. package/dist/components/conversation/conversation-surface.d.ts.map +1 -1
  199. package/dist/components/conversation/conversation-surface.js +2 -0
  200. package/dist/components/conversation/conversation-surface.js.map +1 -1
  201. package/dist/components/conversation/scroll-follow-core.d.ts +24 -0
  202. package/dist/components/conversation/scroll-follow-core.d.ts.map +1 -1
  203. package/dist/components/conversation/scroll-follow-core.js +23 -1
  204. package/dist/components/conversation/scroll-follow-core.js.map +1 -1
  205. package/dist/components/conversation/scroll-follow.d.ts +3 -0
  206. package/dist/components/conversation/scroll-follow.d.ts.map +1 -1
  207. package/dist/components/conversation/scroll-follow.js +80 -1
  208. package/dist/components/conversation/scroll-follow.js.map +1 -1
  209. package/dist/components/ui/attachment/attachment.d.ts +58 -0
  210. package/dist/components/ui/attachment/attachment.d.ts.map +1 -0
  211. package/dist/components/ui/attachment/attachment.js +279 -0
  212. package/dist/components/ui/attachment/attachment.js.map +1 -0
  213. package/dist/components/ui/attachment/index.d.ts +2 -0
  214. package/dist/components/ui/attachment/index.d.ts.map +1 -0
  215. package/dist/components/ui/attachment/index.js +2 -0
  216. package/dist/components/ui/badge/badge.d.ts +1 -1
  217. package/dist/components/ui/bubble/bubble.d.ts +33 -0
  218. package/dist/components/ui/bubble/bubble.d.ts.map +1 -0
  219. package/dist/components/ui/bubble/bubble.js +95 -0
  220. package/dist/components/ui/bubble/bubble.js.map +1 -0
  221. package/dist/components/ui/bubble/index.d.ts +2 -0
  222. package/dist/components/ui/bubble/index.d.ts.map +1 -0
  223. package/dist/components/ui/bubble/index.js +2 -0
  224. package/dist/components/ui/button/button.d.ts +1 -1
  225. package/dist/components/ui/code-block/code-block.d.ts +56 -3
  226. package/dist/components/ui/code-block/code-block.d.ts.map +1 -1
  227. package/dist/components/ui/code-block/code-block.js +231 -50
  228. package/dist/components/ui/code-block/code-block.js.map +1 -1
  229. package/dist/components/ui/code-block/index.d.ts +1 -1
  230. package/dist/components/ui/code-block/index.d.ts.map +1 -1
  231. package/dist/components/ui/code-block/index.js +2 -2
  232. package/dist/components/ui/field/number-field.d.ts +21 -4
  233. package/dist/components/ui/field/number-field.d.ts.map +1 -1
  234. package/dist/components/ui/field/number-field.js +22 -11
  235. package/dist/components/ui/field/number-field.js.map +1 -1
  236. package/dist/components/ui/marker/index.d.ts +2 -0
  237. package/dist/components/ui/marker/index.d.ts.map +1 -0
  238. package/dist/components/ui/marker/index.js +2 -0
  239. package/dist/components/ui/marker/marker.d.ts +35 -0
  240. package/dist/components/ui/marker/marker.d.ts.map +1 -0
  241. package/dist/components/ui/marker/marker.js +123 -0
  242. package/dist/components/ui/marker/marker.js.map +1 -0
  243. package/dist/components/ui/message/cite-ranges.d.ts +42 -0
  244. package/dist/components/ui/message/cite-ranges.d.ts.map +1 -0
  245. package/dist/components/ui/message/cite-ranges.js +105 -0
  246. package/dist/components/ui/message/cite-ranges.js.map +1 -0
  247. package/dist/components/ui/message/index.d.ts +4 -0
  248. package/dist/components/ui/message/index.d.ts.map +1 -0
  249. package/dist/components/ui/message/index.js +4 -0
  250. package/dist/components/ui/message/message.d.ts +95 -0
  251. package/dist/components/ui/message/message.d.ts.map +1 -0
  252. package/dist/components/ui/message/message.js +443 -0
  253. package/dist/components/ui/message/message.js.map +1 -0
  254. package/dist/components/ui/message/parse-message-text.d.ts +93 -0
  255. package/dist/components/ui/message/parse-message-text.d.ts.map +1 -0
  256. package/dist/components/ui/message/parse-message-text.js +365 -0
  257. package/dist/components/ui/message/parse-message-text.js.map +1 -0
  258. package/dist/components/ui/questionnaire/index.d.ts +2 -0
  259. package/dist/components/ui/questionnaire/index.d.ts.map +1 -0
  260. package/dist/components/ui/questionnaire/index.js +2 -0
  261. package/dist/components/ui/questionnaire/questionnaire.d.ts +83 -0
  262. package/dist/components/ui/questionnaire/questionnaire.d.ts.map +1 -0
  263. package/dist/components/ui/questionnaire/questionnaire.js +470 -0
  264. package/dist/components/ui/questionnaire/questionnaire.js.map +1 -0
  265. package/dist/components/ui/status-chip/status-chip.d.ts +1 -1
  266. package/dist/components/ui/switch/switch.js +11 -11
  267. package/dist/components/ui/switch/switch.js.map +1 -1
  268. package/dist/components/ui/trace/index.d.ts +2 -0
  269. package/dist/components/ui/trace/index.d.ts.map +1 -0
  270. package/dist/components/ui/trace/index.js +2 -0
  271. package/dist/components/ui/trace/trace.d.ts +72 -0
  272. package/dist/components/ui/trace/trace.d.ts.map +1 -0
  273. package/dist/components/ui/trace/trace.js +340 -0
  274. package/dist/components/ui/trace/trace.js.map +1 -0
  275. package/dist/index.d.ts +26 -0
  276. package/dist/index.d.ts.map +1 -1
  277. package/dist/index.js +46 -5
  278. package/dist/r/attachment.json +25 -0
  279. package/dist/r/bubble.json +22 -0
  280. package/dist/r/chain-of-thought.json +26 -0
  281. package/dist/r/chat.json +24 -0
  282. package/dist/r/checkpoint.json +35 -0
  283. package/dist/r/confirmation.json +34 -0
  284. package/dist/r/context.json +33 -0
  285. package/dist/r/file-tree.json +32 -0
  286. package/dist/r/inline-citation.json +35 -0
  287. package/dist/r/marker.json +22 -0
  288. package/dist/r/message-scroller.json +31 -0
  289. package/dist/r/message.json +33 -0
  290. package/dist/r/model-selector.json +34 -0
  291. package/dist/r/plan.json +26 -0
  292. package/dist/r/questionnaire.json +28 -0
  293. package/dist/r/queue.json +26 -0
  294. package/dist/r/reasoning.json +26 -0
  295. package/dist/r/registry.json +811 -52
  296. package/dist/r/sources.json +32 -0
  297. package/dist/r/src/components/composites/chain-of-thought/chain-of-thought.tsx +141 -0
  298. package/dist/r/src/components/composites/chain-of-thought/index.ts +11 -0
  299. package/dist/r/src/components/composites/chat/chat.tsx +190 -0
  300. package/dist/r/src/components/composites/chat/index.ts +11 -0
  301. package/dist/r/src/components/composites/checkpoint/checkpoint-model.ts +71 -0
  302. package/dist/r/src/components/composites/checkpoint/checkpoint.tsx +214 -0
  303. package/dist/r/src/components/composites/checkpoint/index.ts +8 -0
  304. package/dist/r/src/components/composites/confirmation/confirmation-model.ts +83 -0
  305. package/dist/r/src/components/composites/confirmation/confirmation.tsx +311 -0
  306. package/dist/r/src/components/composites/confirmation/index.ts +9 -0
  307. package/dist/r/src/components/composites/context/context-model.ts +168 -0
  308. package/dist/r/src/components/composites/context/context.tsx +187 -0
  309. package/dist/r/src/components/composites/context/index.ts +18 -0
  310. package/dist/r/src/components/composites/file-tree/build-file-tree.ts +456 -0
  311. package/dist/r/src/components/composites/file-tree/file-tree.tsx +405 -0
  312. package/dist/r/src/components/composites/file-tree/index.ts +25 -0
  313. package/dist/r/src/components/composites/inline-citation/citation.ts +78 -0
  314. package/dist/r/src/components/composites/inline-citation/index.ts +9 -0
  315. package/dist/r/src/components/composites/inline-citation/inline-citation.tsx +285 -0
  316. package/dist/r/src/components/composites/message-scroller/index.ts +2 -0
  317. package/dist/r/src/components/composites/message-scroller/message-scroller.tsx +301 -0
  318. package/dist/r/src/components/composites/message-scroller/scroll-anchor.ts +170 -0
  319. package/dist/r/src/components/composites/model-selector/index.ts +14 -0
  320. package/dist/r/src/components/composites/model-selector/model-selector.tsx +420 -0
  321. package/dist/r/src/components/composites/model-selector/models.ts +103 -0
  322. package/dist/r/src/components/composites/plan/index.ts +1 -0
  323. package/dist/r/src/components/composites/plan/plan.tsx +155 -0
  324. package/dist/r/src/components/composites/queue/index.ts +10 -0
  325. package/dist/r/src/components/composites/queue/queue.tsx +264 -0
  326. package/dist/r/src/components/composites/reasoning/index.ts +1 -0
  327. package/dist/r/src/components/composites/reasoning/reasoning.tsx +176 -0
  328. package/dist/r/src/components/composites/sources/index.ts +11 -0
  329. package/dist/r/src/components/composites/sources/source.ts +116 -0
  330. package/dist/r/src/components/composites/sources/sources.tsx +163 -0
  331. package/dist/r/src/components/composites/stack-trace/index.ts +19 -0
  332. package/dist/r/src/components/composites/stack-trace/parse-stack-trace.ts +507 -0
  333. package/dist/r/src/components/composites/stack-trace/stack-trace.tsx +395 -0
  334. package/dist/r/src/components/composites/subagent/index.ts +1 -0
  335. package/dist/r/src/components/composites/subagent/subagent.tsx +159 -0
  336. package/dist/r/src/components/composites/suggestion/index.ts +1 -0
  337. package/dist/r/src/components/composites/suggestion/suggestion.tsx +140 -0
  338. package/dist/r/src/components/composites/task/index.ts +14 -0
  339. package/dist/r/src/components/composites/task/task.tsx +317 -0
  340. package/dist/r/src/components/composites/terminal/ansi.ts +674 -0
  341. package/dist/r/src/components/composites/terminal/index.ts +20 -0
  342. package/dist/r/src/components/composites/terminal/terminal-model.ts +111 -0
  343. package/dist/r/src/components/composites/terminal/terminal.tsx +574 -0
  344. package/dist/r/src/components/composites/test-results/index.ts +20 -0
  345. package/dist/r/src/components/composites/test-results/test-results-model.ts +368 -0
  346. package/dist/r/src/components/composites/test-results/test-results.tsx +586 -0
  347. package/dist/r/src/components/composites/tool/format-tool-value.ts +221 -0
  348. package/dist/r/src/components/composites/tool/index.ts +2 -0
  349. package/dist/r/src/components/composites/tool/tool.tsx +228 -0
  350. package/dist/r/src/components/conversation/conversation-surface.tsx +9 -0
  351. package/dist/r/src/components/conversation/scroll-follow-core.ts +31 -0
  352. package/dist/r/src/components/conversation/scroll-follow.ts +92 -0
  353. package/dist/r/src/components/ui/attachment/attachment.tsx +282 -0
  354. package/dist/r/src/components/ui/attachment/index.ts +10 -0
  355. package/dist/r/src/components/ui/bubble/bubble.tsx +86 -0
  356. package/dist/r/src/components/ui/bubble/index.ts +1 -0
  357. package/dist/r/src/components/ui/code-block/code-block.tsx +256 -26
  358. package/dist/r/src/components/ui/code-block/index.ts +9 -1
  359. package/dist/r/src/components/ui/field/number-field.tsx +51 -14
  360. package/dist/r/src/components/ui/marker/index.ts +1 -0
  361. package/dist/r/src/components/ui/marker/marker.tsx +90 -0
  362. package/dist/r/src/components/ui/message/cite-ranges.ts +144 -0
  363. package/dist/r/src/components/ui/message/index.ts +23 -0
  364. package/dist/r/src/components/ui/message/message.tsx +434 -0
  365. package/dist/r/src/components/ui/message/parse-message-text.ts +450 -0
  366. package/dist/r/src/components/ui/questionnaire/index.ts +10 -0
  367. package/dist/r/src/components/ui/questionnaire/questionnaire.tsx +446 -0
  368. package/dist/r/src/components/ui/trace/index.ts +9 -0
  369. package/dist/r/src/components/ui/trace/trace.tsx +334 -0
  370. package/dist/r/src/styles/base.css +34 -0
  371. package/dist/r/stack-trace.json +32 -0
  372. package/dist/r/subagent.json +27 -0
  373. package/dist/r/suggestion.json +24 -0
  374. package/dist/r/task.json +28 -0
  375. package/dist/r/terminal.json +35 -0
  376. package/dist/r/test-results.json +33 -0
  377. package/dist/r/tool.json +31 -0
  378. package/dist/r/trace.json +25 -0
  379. package/package.json +6 -3
  380. package/registry.json +811 -52
  381. package/src/components/composites/chain-of-thought/chain-of-thought.tsx +141 -0
  382. package/src/components/composites/chain-of-thought/index.ts +11 -0
  383. package/src/components/composites/chat/chat.tsx +190 -0
  384. package/src/components/composites/chat/index.ts +11 -0
  385. package/src/components/composites/checkpoint/checkpoint-model.ts +71 -0
  386. package/src/components/composites/checkpoint/checkpoint.tsx +214 -0
  387. package/src/components/composites/checkpoint/index.ts +8 -0
  388. package/src/components/composites/confirmation/confirmation-model.ts +83 -0
  389. package/src/components/composites/confirmation/confirmation.tsx +311 -0
  390. package/src/components/composites/confirmation/index.ts +9 -0
  391. package/src/components/composites/context/context-model.ts +168 -0
  392. package/src/components/composites/context/context.tsx +187 -0
  393. package/src/components/composites/context/index.ts +18 -0
  394. package/src/components/composites/file-tree/build-file-tree.ts +456 -0
  395. package/src/components/composites/file-tree/file-tree.tsx +405 -0
  396. package/src/components/composites/file-tree/index.ts +25 -0
  397. package/src/components/composites/inline-citation/citation.ts +78 -0
  398. package/src/components/composites/inline-citation/index.ts +9 -0
  399. package/src/components/composites/inline-citation/inline-citation.tsx +285 -0
  400. package/src/components/composites/message-scroller/index.ts +2 -0
  401. package/src/components/composites/message-scroller/message-scroller.tsx +301 -0
  402. package/src/components/composites/message-scroller/scroll-anchor.ts +170 -0
  403. package/src/components/composites/model-selector/index.ts +14 -0
  404. package/src/components/composites/model-selector/model-selector.tsx +420 -0
  405. package/src/components/composites/model-selector/models.ts +103 -0
  406. package/src/components/composites/plan/index.ts +1 -0
  407. package/src/components/composites/plan/plan.tsx +155 -0
  408. package/src/components/composites/queue/index.ts +10 -0
  409. package/src/components/composites/queue/queue.tsx +264 -0
  410. package/src/components/composites/reasoning/index.ts +1 -0
  411. package/src/components/composites/reasoning/reasoning.tsx +176 -0
  412. package/src/components/composites/sources/index.ts +11 -0
  413. package/src/components/composites/sources/source.ts +116 -0
  414. package/src/components/composites/sources/sources.tsx +163 -0
  415. package/src/components/composites/stack-trace/index.ts +19 -0
  416. package/src/components/composites/stack-trace/parse-stack-trace.ts +507 -0
  417. package/src/components/composites/stack-trace/stack-trace.tsx +395 -0
  418. package/src/components/composites/subagent/index.ts +1 -0
  419. package/src/components/composites/subagent/subagent.tsx +159 -0
  420. package/src/components/composites/suggestion/index.ts +1 -0
  421. package/src/components/composites/suggestion/suggestion.tsx +140 -0
  422. package/src/components/composites/task/index.ts +14 -0
  423. package/src/components/composites/task/task.tsx +317 -0
  424. package/src/components/composites/terminal/ansi.ts +674 -0
  425. package/src/components/composites/terminal/index.ts +20 -0
  426. package/src/components/composites/terminal/terminal-model.ts +111 -0
  427. package/src/components/composites/terminal/terminal.tsx +574 -0
  428. package/src/components/composites/test-results/index.ts +20 -0
  429. package/src/components/composites/test-results/test-results-model.ts +368 -0
  430. package/src/components/composites/test-results/test-results.tsx +586 -0
  431. package/src/components/composites/tool/format-tool-value.ts +221 -0
  432. package/src/components/composites/tool/index.ts +2 -0
  433. package/src/components/composites/tool/tool.tsx +228 -0
  434. package/src/components/conversation/conversation-surface.tsx +9 -0
  435. package/src/components/conversation/scroll-follow-core.ts +31 -0
  436. package/src/components/conversation/scroll-follow.ts +92 -0
  437. package/src/components/ui/attachment/attachment.tsx +282 -0
  438. package/src/components/ui/attachment/index.ts +10 -0
  439. package/src/components/ui/bubble/bubble.tsx +86 -0
  440. package/src/components/ui/bubble/index.ts +1 -0
  441. package/src/components/ui/code-block/code-block.tsx +256 -26
  442. package/src/components/ui/code-block/index.ts +9 -1
  443. package/src/components/ui/field/number-field.tsx +51 -14
  444. package/src/components/ui/marker/index.ts +1 -0
  445. package/src/components/ui/marker/marker.tsx +90 -0
  446. package/src/components/ui/message/cite-ranges.ts +144 -0
  447. package/src/components/ui/message/index.ts +23 -0
  448. package/src/components/ui/message/message.tsx +434 -0
  449. package/src/components/ui/message/parse-message-text.ts +450 -0
  450. package/src/components/ui/questionnaire/index.ts +10 -0
  451. package/src/components/ui/questionnaire/questionnaire.tsx +446 -0
  452. package/src/components/ui/trace/index.ts +9 -0
  453. package/src/components/ui/trace/trace.tsx +334 -0
  454. package/src/index.ts +26 -0
  455. package/src/styles/base.css +34 -0
@@ -1,7 +1,11 @@
1
1
  import {
2
+ createEffect,
2
3
  createMemo,
3
4
  createSignal,
4
5
  For,
6
+ on,
7
+ onCleanup,
8
+ onMount,
5
9
  Show,
6
10
  splitProps,
7
11
  type ComponentProps,
@@ -38,8 +42,9 @@ import { cn } from '#lib/utils'
38
42
  * **The scroller is focusable and named.** A horizontally scrollable region has
39
43
  * to be reachable by keyboard — this is axe's `scrollable-region-focusable`, and
40
44
  * a region that scrolls but cannot be focused is a WCAG 2.1.1 failure. It is a
41
- * `region` with a label rather than a bare `tabindex`, so the tab stop announces
42
- * what it is.
45
+ * labelled `group` rather than a bare `tabindex`, so the tab stop announces what
46
+ * it is. It is deliberately not a `region` landmark: a transcript holds many
47
+ * blocks, often in one language, and repeated landmarks of one name are noise.
43
48
  *
44
49
  * **Resolving a streaming block must not move the reader.** When `complete` is
45
50
  * false the block shows the code it has plus a generating indicator; the
@@ -47,8 +52,35 @@ import { cn } from '#lib/utils'
47
52
  * block that grows the moment its content resolves shifts everything below it.
48
53
  * If a caller's `highlight` changes the line box, that is the caller's height to
49
54
  * hold — `lineHeight` is a prop for exactly that reason.
55
+ *
56
+ * ## Output, not only source
57
+ *
58
+ * The same surface carries terminal output, logs and diffs inside an agent's
59
+ * activity, so it also:
60
+ *
61
+ * - **loads its highlighter lazily** (`loadHighlight`). The grammar is fetched
62
+ * only for a block that is complete and has a language, the block renders plain
63
+ * until it arrives, and a loader that returns nothing — an unknown language, a
64
+ * failed fetch — leaves the plain text in place without an error. Highlighting
65
+ * a block on every streamed delta would re-tokenise the whole thing per token,
66
+ * so a streaming block stays plain until `complete`.
67
+ * - **marks lines** (`lineMarks`) as added, removed, highlighted or failed. A mark
68
+ * is carried by a gutter glyph and by `<ins>`/`<del>` for the two that change
69
+ * text, never by colour alone, and the glyph is not selectable so a copied
70
+ * selection stays the source.
71
+ * - **copies the source exactly.** The copy button writes `code` as given: no
72
+ * trailing-newline trimming, no line numbers, no gutter glyphs, and the whole
73
+ * block even when only part of it is rendered (`lineLimit`).
74
+ * - **bounds a large render.** Past `lineLimit` lines the per-line renderer and a
75
+ * highlighted render show the first lines and a control to show the rest,
76
+ * because tens of thousands of row elements, or a tokenizer run over all of
77
+ * them, are a freeze, not a transcript. Which renderer is in use is decided
78
+ * at the time, so a highlighter that loads late takes over the bound from the
79
+ * per-line rows and the note below the block always describes what is drawn.
80
+ * The plain renderer is a single text node and needs no limit.
81
+ * - **comes in a small size** (`size="sm"`) for tool output inside a Trace line.
50
82
  */
51
- export type CodeBlockProps = Omit<ComponentProps<'div'>, 'children'> & {
83
+ export type CodeBlockProps = Omit<ComponentProps<'div'>, 'children' | 'onCopy'> & {
52
84
  code: string
53
85
  /** The language, shown in the header and used as the region's label. */
54
86
  language?: string
@@ -82,8 +114,35 @@ export type CodeBlockProps = Omit<ComponentProps<'div'>, 'children'> & {
82
114
  * any `pre` inside `highlight` output; line numbers stay on the first visual line.
83
115
  */
84
116
  wrap?: boolean
117
+ /** `sm` is the compact chrome for output nested inside a Trace line. */
118
+ size?: 'default' | 'sm'
119
+ /**
120
+ * Marks on 1-based line numbers. Applies to the per-line renderer, which is
121
+ * used whenever marks or line numbers are present and no highlighter is in use,
122
+ * given as `highlight` or loaded by `loadHighlight`: a highlighter replaces the
123
+ * rows, so the marks and the gutter go with them.
124
+ */
125
+ lineMarks?: Readonly<Record<number, CodeLineMark>>
126
+ /**
127
+ * Resolve a highlighter for the block's language. Called once the block is
128
+ * complete; resolving to `undefined` (or rejecting) keeps the plain rendering.
129
+ */
130
+ loadHighlight?: (language: string | undefined) => Promise<CodeHighlighter | undefined>
131
+ /**
132
+ * Lines the per-line and the highlighted renderer show before offering the
133
+ * rest. Default 2000. The plain renderer is one text node and is not limited.
134
+ */
135
+ lineLimit?: number
136
+ /** Called after each copy attempt with whether the clipboard accepted it. */
137
+ onCopy?: (ok: boolean) => void
85
138
  }
86
139
 
140
+ export type CodeLineMark = 'add' | 'remove' | 'highlight' | 'error'
141
+ export type CodeHighlighter = (code: string) => JSX.Element
142
+
143
+ /** Lines the per-line renderer shows before it offers the rest. */
144
+ export const CODE_BLOCK_LINE_LIMIT = 2_000
145
+
87
146
  /** The height a block must exceed before its actions are repeated. */
88
147
  export const TALL_CODE_BLOCK_PX = 480
89
148
 
@@ -118,6 +177,11 @@ export function CodeBlock(props: CodeBlockProps) {
118
177
  'tallThreshold',
119
178
  'maxHeight',
120
179
  'wrap',
180
+ 'size',
181
+ 'lineMarks',
182
+ 'loadHighlight',
183
+ 'lineLimit',
184
+ 'onCopy',
121
185
  'class',
122
186
  'ref',
123
187
  ])
@@ -126,9 +190,52 @@ export function CodeBlock(props: CodeBlockProps) {
126
190
  const [failed, setFailed] = createSignal(false)
127
191
  const [tall, setTall] = createSignal(false)
128
192
 
129
- const label = () => local.title ?? local.language ?? 'code'
130
- const regionLabel = () => (local.language ? `${local.language} code` : 'code')
193
+ const [loaded, setLoaded] = createSignal<CodeHighlighter>()
194
+ const [showAll, setShowAll] = createSignal(false)
195
+ let bodyElement: HTMLDivElement | undefined
196
+
197
+ // A language string can come from untrusted model output. It is rendered as
198
+ // text, so it cannot inject markup; the cap keeps a pathological one from
199
+ // swallowing the header.
200
+ const language = () => local.language?.trim().slice(0, 40) || undefined
201
+ const label = () => local.title ?? language() ?? 'code'
202
+ const groupLabel = () => (language() ? `${language()} code` : 'code')
203
+ const small = () => local.size === 'sm'
131
204
  const lines = createMemo(() => local.code.replace(/\n$/, '').split('\n'))
205
+ const lineLimit = () => local.lineLimit ?? CODE_BLOCK_LINE_LIMIT
206
+ const visibleLines = createMemo(() => (showAll() ? lines() : lines().slice(0, lineLimit())))
207
+ const hiddenLines = () => lines().length - visibleLines().length
208
+
209
+ // Load once the block has stopped changing. `on` keys the effect to the
210
+ // language and completion, not to every streamed character, and a stale
211
+ // resolution (the language changed while the grammar was in flight) is dropped.
212
+ createEffect(
213
+ on(
214
+ () => [local.complete, language(), local.loadHighlight] as const,
215
+ ([complete, lang, load]) => {
216
+ setLoaded(undefined)
217
+ if (!complete || !load || local.highlight) return
218
+ let current = true
219
+ onCleanup(() => (current = false))
220
+ // Wrapped, not called bare: a loader that throws before it returns a promise
221
+ // (a bad import path, a missing grammar table) must degrade to plain text
222
+ // like one that rejects, not tear down the tree from inside this effect.
223
+ new Promise<CodeHighlighter | undefined>((resolve) => resolve(load(lang))).then(
224
+ (highlighter) => {
225
+ if (current && highlighter) setLoaded(() => highlighter)
226
+ },
227
+ () => undefined
228
+ )
229
+ }
230
+ )
231
+ )
232
+ const highlighter = (): CodeHighlighter | undefined => local.highlight ?? loaded()
233
+ // The renderer in use decides everything about the limit, not the props alone:
234
+ // a highlighter that has loaded since the first render replaces the per-line
235
+ // rows, so what is drawn, and what the footer may say, follows `highlighter()`.
236
+ const perLine = () =>
237
+ highlighter() === undefined && (local.showLineNumbers === true || local.lineMarks !== undefined)
238
+ const truncated = () => hiddenLines() > 0 && (highlighter() !== undefined || perLine())
132
239
  const maxHeight = () =>
133
240
  typeof local.maxHeight === 'number' ? `${local.maxHeight}px` : local.maxHeight
134
241
 
@@ -136,15 +243,17 @@ export function CodeBlock(props: CodeBlockProps) {
136
243
  const ok = await copyText(local.code)
137
244
  setCopied(ok)
138
245
  setFailed(!ok)
246
+ local.onCopy?.(ok)
139
247
  if (ok) setTimeout(() => setCopied(false), 1500)
140
248
  }
141
249
 
142
250
  const Actions = () => (
143
- <div class="flex items-center gap-1 opacity-0 transition-opacity group-focus-within/code:opacity-100 group-hover/code:opacity-100">
251
+ <div class="flex items-center gap-1 opacity-0 transition-opacity group-focus-within/code:opacity-100 group-hover/code:opacity-100 [@media(hover:none)]:opacity-100">
144
252
  {local.actions}
145
253
  <Button
146
254
  variant="ghost"
147
255
  size="icon-2xs"
256
+ touchTarget="comfortable"
148
257
  aria-label={copied() ? (local.copiedLabel ?? 'Copied') : (local.copyLabel ?? 'Copy code')}
149
258
  title={failed() ? 'Copying is unavailable in this context' : undefined}
150
259
  onClick={() => void copy()}
@@ -158,7 +267,13 @@ export function CodeBlock(props: CodeBlockProps) {
158
267
 
159
268
  return (
160
269
  <div
161
- class={cn('group/code overflow-hidden rounded-xl border border-border bg-card', local.class)}
270
+ data-slot="code-block"
271
+ data-size={local.size ?? 'default'}
272
+ class={cn(
273
+ 'group/code overflow-hidden border border-border bg-card',
274
+ small() ? 'rounded-lg' : 'rounded-xl',
275
+ local.class
276
+ )}
162
277
  {...rest}
163
278
  ref={(element) => {
164
279
  // Composed rather than replaced: a caller's ref must survive.
@@ -166,17 +281,33 @@ export function CodeBlock(props: CodeBlockProps) {
166
281
  else if (local.ref) local.ref = element
167
282
  // Measured rather than assumed: the caller controls the content, so only
168
283
  // the rendered box can say whether the action row has scrolled away.
284
+ // The body is what is watched, not the block: the repeated action row is
285
+ // added to the block, so watching the block made this callback resize the
286
+ // very element it observes, which is a ResizeObserver loop (WebKit reports
287
+ // it as an uncaught "loop completed with undelivered notifications" error).
288
+ // The footer's own height is left out of the measure for the same reason: a
289
+ // block is tall by its content, not by the row that tallness adds.
169
290
  const observer = new ResizeObserver(() => {
170
- setTall(element.offsetHeight > (local.tallThreshold ?? TALL_CODE_BLOCK_PX))
291
+ const footer = element.querySelector<HTMLElement>('[data-code-block-footer]')
292
+ setTall(
293
+ element.offsetHeight - (footer?.offsetHeight ?? 0) >
294
+ (local.tallThreshold ?? TALL_CODE_BLOCK_PX)
295
+ )
296
+ })
297
+ onMount(() => {
298
+ if (bodyElement) observer.observe(bodyElement)
171
299
  })
172
- observer.observe(element)
300
+ onCleanup(() => observer.disconnect())
173
301
  }}
174
302
  >
175
- <div class="flex items-center justify-between gap-2 px-3 py-1">
303
+ <div
304
+ class={cn('flex items-center justify-between gap-2', small() ? 'px-2 py-0.5' : 'px-3 py-1')}
305
+ >
176
306
  <span class="truncate font-code text-code text-muted-foreground">{label()}</span>
177
307
  <Actions />
178
308
  </div>
179
309
  <div
310
+ ref={(element) => (bodyElement = element)}
180
311
  data-slot="code-block-body"
181
312
  data-wrap={local.wrap ? '' : undefined}
182
313
  class={cn('scroll-fade overflow-x-auto', {
@@ -187,27 +318,31 @@ export function CodeBlock(props: CodeBlockProps) {
187
318
  })}
188
319
  style={maxHeight() === undefined ? undefined : { 'max-height': maxHeight() }}
189
320
  // A region that scrolls must be focusable, and a tab stop needs a name.
321
+ // A `group`, not a `region`: a landmark with the same role and name as the
322
+ // next block's ("ts code" twice) is a duplicate in the screen reader's
323
+ // landmark list, and a long answer would fill that list with code blocks.
190
324
  tabindex="0"
191
- role="region"
192
- aria-label={regionLabel()}
325
+ role="group"
326
+ aria-label={groupLabel()}
193
327
  >
194
328
  <Show
195
- when={local.highlight}
329
+ when={highlighter()}
196
330
  fallback={
197
- <pre class="m-0 px-3 py-2" style={{ 'line-height': local.lineHeight ?? '1.5' }}>
331
+ <pre
332
+ class={cn('m-0', small() ? 'px-2 py-1.5' : 'px-3 py-2')}
333
+ style={{ 'line-height': local.lineHeight ?? '1.5' }}
334
+ >
198
335
  <code class="font-code text-code">
199
- <Show when={local.showLineNumbers} fallback={local.code.replace(/\n$/, '')}>
200
- <For each={lines()}>
336
+ <Show when={perLine()} fallback={local.code.replace(/\n$/, '')}>
337
+ <For each={visibleLines()}>
201
338
  {(line, index) => (
202
- <span class="grid grid-cols-[3ch_1fr] gap-3">
203
- <span
204
- class="text-right text-muted-foreground select-none"
205
- aria-hidden="true"
206
- >
207
- {index() + 1}
208
- </span>
209
- <span class={cn({ 'min-w-0': local.wrap })}>{line || ' '}</span>
210
- </span>
339
+ <CodeLine
340
+ line={line}
341
+ number={index() + 1}
342
+ numbered={local.showLineNumbers === true}
343
+ mark={local.lineMarks?.[index() + 1]}
344
+ wrap={local.wrap === true}
345
+ />
211
346
  )}
212
347
  </For>
213
348
  </Show>
@@ -215,7 +350,31 @@ export function CodeBlock(props: CodeBlockProps) {
215
350
  </pre>
216
351
  }
217
352
  >
218
- {(highlight) => <div class="px-3 py-2">{highlight()(local.code)}</div>}
353
+ {(highlight) => (
354
+ <div class={small() ? 'px-2 py-1.5' : 'px-3 py-2'}>
355
+ {highlight()(hiddenLines() > 0 ? visibleLines().join('\n') : local.code)}
356
+ </div>
357
+ )}
358
+ </Show>
359
+ <Show when={truncated()}>
360
+ <div class="flex items-center gap-2 border-t border-border px-3 py-1 text-xs text-muted-foreground">
361
+ <span>
362
+ Showing the first {visibleLines().length.toLocaleString()} of{' '}
363
+ {lines().length.toLocaleString()} lines.
364
+ </span>
365
+ <Button
366
+ variant="ghost"
367
+ size="2xs"
368
+ onClick={() => {
369
+ setShowAll(true)
370
+ // This button leaves the document with the click; the scroller
371
+ // is the nearest place focus can stay, so a keyboard user keeps their place.
372
+ bodyElement?.focus({ preventScroll: true })
373
+ }}
374
+ >
375
+ Show all {lines().length.toLocaleString()} lines
376
+ </Button>
377
+ </div>
219
378
  </Show>
220
379
  {/*
221
380
  In the scroller's box, and a single line: the indicator must not add
@@ -238,6 +397,77 @@ export function CodeBlock(props: CodeBlockProps) {
238
397
  )
239
398
  }
240
399
 
400
+ const MARK_GLYPH: Readonly<Record<CodeLineMark, string>> = {
401
+ add: '+',
402
+ remove: '−',
403
+ highlight: '',
404
+ error: '!',
405
+ }
406
+
407
+ /**
408
+ * One rendered line. The gutter glyph and the element (`ins`/`del`) carry what a
409
+ * mark means so it survives greyscale and a screen reader; both gutters are
410
+ * unselectable so dragging across the block and copying yields only source.
411
+ */
412
+ function CodeLine(props: {
413
+ line: string
414
+ number: number
415
+ numbered: boolean
416
+ mark?: CodeLineMark
417
+ wrap: boolean
418
+ }) {
419
+ const content = () => (
420
+ <>
421
+ <Show when={props.numbered}>
422
+ <span class="text-right text-muted-foreground select-none" aria-hidden="true">
423
+ {props.number}
424
+ </span>
425
+ </Show>
426
+ <span
427
+ class="w-[1ch] text-center text-muted-foreground select-none"
428
+ aria-hidden="true"
429
+ data-slot="code-line-mark"
430
+ >
431
+ {props.mark ? MARK_GLYPH[props.mark] : ''}
432
+ </span>
433
+ <span class={cn({ 'min-w-0': props.wrap })}>{props.line || ' '}</span>
434
+ </>
435
+ )
436
+ const rowClass = () =>
437
+ cn(
438
+ 'grid gap-3 no-underline',
439
+ props.numbered ? 'grid-cols-[3ch_1ch_1fr]' : 'grid-cols-[1ch_1fr]',
440
+ {
441
+ 'bg-success-subtle': props.mark === 'add',
442
+ 'bg-destructive-subtle': props.mark === 'remove' || props.mark === 'error',
443
+ 'bg-primary-subtle': props.mark === 'highlight',
444
+ }
445
+ )
446
+ return (
447
+ <Show
448
+ when={props.mark === 'add' || props.mark === 'remove'}
449
+ fallback={
450
+ <span data-mark={props.mark} class={rowClass()}>
451
+ {content()}
452
+ </span>
453
+ }
454
+ >
455
+ <Show
456
+ when={props.mark === 'add'}
457
+ fallback={
458
+ <del data-mark="remove" class={rowClass()}>
459
+ {content()}
460
+ </del>
461
+ }
462
+ >
463
+ <ins data-mark="add" class={rowClass()}>
464
+ {content()}
465
+ </ins>
466
+ </Show>
467
+ </Show>
468
+ )
469
+ }
470
+
241
471
  /**
242
472
  * InlineCode.
243
473
  *
@@ -1 +1,9 @@
1
- export { CodeBlock, InlineCode, TALL_CODE_BLOCK_PX, type CodeBlockProps } from './code-block'
1
+ export {
2
+ CODE_BLOCK_LINE_LIMIT,
3
+ CodeBlock,
4
+ InlineCode,
5
+ TALL_CODE_BLOCK_PX,
6
+ type CodeBlockProps,
7
+ type CodeHighlighter,
8
+ type CodeLineMark,
9
+ } from './code-block'
@@ -2,10 +2,9 @@ import { createEffect, createSignal, type JSX } from 'solid-js'
2
2
  import { FormField } from './field'
3
3
  import { Input } from '../input/input'
4
4
 
5
- export type NumberFieldProps = {
5
+ type NumberFieldBaseProps = {
6
6
  label: string
7
7
  hint?: string
8
- value: number
9
8
  min: number
10
9
  max: number
11
10
  /**
@@ -23,20 +22,44 @@ export type NumberFieldProps = {
23
22
  * `integer={false}`, and `min={0.5} step={1}` accepts 0.5, 1.5, 2.5.
24
23
  */
25
24
  integer?: boolean
26
- onChange: (value: number) => void
25
+ /** Locks the input; a locked field keeps its value and reports nothing. */
26
+ disabled?: boolean
27
27
  class?: string
28
28
  onBlur?: JSX.EventHandler<HTMLInputElement, FocusEvent>
29
29
  }
30
30
 
31
+ export type NumberFieldProps = NumberFieldBaseProps &
32
+ (
33
+ | {
34
+ optional?: false
35
+ value: number
36
+ onChange: (value: number) => void
37
+ }
38
+ | {
39
+ /**
40
+ * Lets the field be left blank: a blank field is valid and reports `null`,
41
+ * and a `null` value shows a blank field. Use it for a limit that falls
42
+ * back to a default when unset, so a caller never maps `''` to
43
+ * `undefined` of its own.
44
+ */
45
+ optional: true
46
+ value: number | null
47
+ onChange: (value: number | null) => void
48
+ }
49
+ )
50
+
51
+ const text = (value: number | null) => (value === null ? '' : String(value))
52
+
31
53
  /**
32
54
  * A controlled numeric field that keeps an editable draft while validating
33
55
  * range, integer and step constraints. Invalid drafts are announced and restored
34
56
  * to the latest controlled value when focus leaves the input, so `onChange`
35
57
  * only ever receives a value the field accepts — a caller never needs a
36
- * `Number(value) || fallback` of its own.
58
+ * `Number(value) || fallback` of its own. With `optional`, blank is accepted and
59
+ * reported as `null`.
37
60
  */
38
61
  export function NumberField(props: NumberFieldProps) {
39
- const [draft, setDraft] = createSignal(String(props.value))
62
+ const [draft, setDraft] = createSignal(text(props.value))
40
63
  const [error, setError] = createSignal('')
41
64
  // Whole numbers only when nothing on the grid is fractional: a whole step from
42
65
  // a fractional `min` (0.5, 1.5, 2.5) puts the spinner's own values off the
@@ -46,11 +69,15 @@ export function NumberField(props: NumberFieldProps) {
46
69
  (props.step === undefined || (Number.isInteger(props.step) && Number.isInteger(props.min)))
47
70
 
48
71
  createEffect(() => {
49
- setDraft(String(props.value))
72
+ setDraft(text(props.value))
50
73
  })
51
74
 
52
- const validate = (raw: string) => {
53
- if (!raw) return `${props.label} is required.`
75
+ // A number input reports '' both when it is empty and when it holds text it cannot parse
76
+ // ("abc", "-", "1e"); only `validity.badInput` tells them apart, and a bad draft must never
77
+ // count as blank (it would report `null` and clear the limit).
78
+ const validate = (raw: string, badInput: boolean) => {
79
+ if (badInput) return `${props.label} must be a valid number.`
80
+ if (!raw) return props.optional ? '' : `${props.label} is required.`
54
81
  const next = Number(raw)
55
82
  if (!Number.isFinite(next)) return `${props.label} must be a valid number.`
56
83
  if (integer() && !Number.isInteger(next)) {
@@ -80,19 +107,29 @@ export function NumberField(props: NumberFieldProps) {
80
107
  min={props.min}
81
108
  max={props.max}
82
109
  step={props.step ?? (integer() ? 1 : 'any')}
83
- required
110
+ required={!props.optional}
111
+ disabled={props.disabled}
84
112
  onInput={(event) => {
85
113
  const raw = event.currentTarget.value
86
- setDraft(raw)
87
- const nextError = validate(raw)
114
+ // Read before touching the draft: writing '' back to the input would clear the entry and
115
+ // with it `badInput`. An unparsable entry keeps the last draft and the text on screen, so
116
+ // the user can correct it; blur restores the last good value.
117
+ const badInput = event.currentTarget.validity.badInput
118
+ if (!badInput) setDraft(raw)
119
+ const nextError = validate(raw, badInput)
88
120
  setError(nextError)
89
- if (!nextError) props.onChange(Number(raw))
121
+ if (nextError) return
122
+ // `optional` narrows the callback to `number | null`; a required field never sees `''`.
123
+ ;(props.onChange as (value: number | null) => void)(raw ? Number(raw) : null)
90
124
  }}
91
125
  onBlur={(event) => {
92
- const nextError = validate(draft())
126
+ const nextError = validate(draft(), event.currentTarget.validity.badInput)
93
127
  if (nextError) {
94
- setDraft(String(props.value))
128
+ setDraft(text(props.value))
95
129
  setError('')
130
+ // The draft of an unparsable entry is '' and so is the restored blank value: the signal
131
+ // does not change, so the DOM has to be reset by hand to drop the leftover text.
132
+ event.currentTarget.value = text(props.value)
96
133
  }
97
134
  props.onBlur?.(event)
98
135
  }}
@@ -0,0 +1 @@
1
+ export { Marker, markerVariants, type MarkerProps } from './marker'
@@ -0,0 +1,90 @@
1
+ import { Show, splitProps, type ComponentProps, type JSX } from 'solid-js'
2
+ import { cn } from '#lib/utils'
3
+ import { cva, type VariantProps } from '#lib/variants'
4
+
5
+ /**
6
+ * Marker.
7
+ *
8
+ * A note or divider *between* turns: a day change, a reconnect, a cancelled run,
9
+ * an event the transcript does not recognise. It is deliberately the quietest
10
+ * element in the column — a hairline with a label — because the transcript has
11
+ * dozens of these and any one that shouts teaches the reader to stop looking.
12
+ *
13
+ * `variant="rule"` draws the hairline either side (a boundary: "Today",
14
+ * "Reconnected"); `variant="note"` is a bare line of text with its mark (an
15
+ * observation that sits inside the flow). `tone` colours the mark and label and
16
+ * is never the only signal — the `label` always says it in words.
17
+ *
18
+ * A marker is static by default. Pass `live` for one that reports a change the
19
+ * reader must not miss (connection lost): it becomes a status region (`polite`)
20
+ * or an alert (`assertive`). A divider is not an ARIA separator, because
21
+ * `separator` is defined to carry no content.
22
+ */
23
+ export const markerVariants = cva('flex min-w-0 items-center gap-3 text-xs', {
24
+ variants: {
25
+ tone: {
26
+ neutral: 'text-muted-foreground',
27
+ info: 'text-info',
28
+ success: 'text-success',
29
+ warning: 'text-warning',
30
+ danger: 'text-destructive',
31
+ },
32
+ variant: {
33
+ rule: 'w-full',
34
+ note: 'w-full justify-start',
35
+ },
36
+ },
37
+ defaultVariants: { tone: 'neutral', variant: 'rule' },
38
+ })
39
+
40
+ export type MarkerProps = Omit<ComponentProps<'div'>, 'children'> &
41
+ VariantProps<typeof markerVariants> & {
42
+ label: JSX.Element
43
+ icon?: JSX.Element
44
+ /** Secondary text after the label: a time, a count. */
45
+ description?: JSX.Element
46
+ /** A control that belongs to the note: Retry, Reconnect. */
47
+ action?: JSX.Element
48
+ live?: 'polite' | 'assertive'
49
+ }
50
+
51
+ export function Marker(props: MarkerProps) {
52
+ const [local, rest] = splitProps(props, [
53
+ 'class',
54
+ 'tone',
55
+ 'variant',
56
+ 'label',
57
+ 'icon',
58
+ 'description',
59
+ 'action',
60
+ 'live',
61
+ ])
62
+ const rule = () => (local.variant ?? 'rule') === 'rule'
63
+ return (
64
+ <div
65
+ data-slot="marker"
66
+ role={local.live === 'assertive' ? 'alert' : local.live === 'polite' ? 'status' : undefined}
67
+ class={cn(markerVariants({ tone: local.tone, variant: local.variant }), local.class)}
68
+ {...rest}
69
+ >
70
+ <Show when={rule()}>
71
+ <span aria-hidden="true" class="h-px min-w-4 flex-1 bg-border" />
72
+ </Show>
73
+ <span class="flex min-w-0 items-center gap-1.5">
74
+ <Show when={local.icon}>
75
+ <span aria-hidden="true" class="grid shrink-0 place-items-center [&_svg]:size-3.5">
76
+ {local.icon}
77
+ </span>
78
+ </Show>
79
+ <span class="font-medium [overflow-wrap:anywhere]">{local.label}</span>
80
+ <Show when={local.description}>
81
+ <span class="text-muted-foreground [overflow-wrap:anywhere]">{local.description}</span>
82
+ </Show>
83
+ <Show when={local.action}>{local.action}</Show>
84
+ </span>
85
+ <Show when={rule()}>
86
+ <span aria-hidden="true" class="h-px min-w-4 flex-1 bg-border" />
87
+ </Show>
88
+ </div>
89
+ )
90
+ }