@elabs-ai/components-ai 4.2.0 → 5.0.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 (462) hide show
  1. package/README.md +1 -1
  2. package/dist/{_audio-player-media-chrome-T3XVXWRZ.js → _audio-player-media-chrome.js} +1 -1
  3. package/dist/_code-block-theme.js +12 -0
  4. package/dist/_code-block-theme.js.map +1 -0
  5. package/dist/{_flow-boundary-SHNWLQG5.js → _flow-boundary.js} +1 -1
  6. package/dist/_flow-boundary.js.map +1 -0
  7. package/dist/_flow-lazy.js +8 -0
  8. package/dist/_flow-lazy.js.map +1 -0
  9. package/dist/_lazy-boundary-conformance.js +2 -0
  10. package/dist/_lazy-boundary-conformance.js.map +1 -0
  11. package/dist/_lazy-cjk.js +13 -0
  12. package/dist/_lazy-cjk.js.map +1 -0
  13. package/dist/_lazy-engine-boundary.js +9 -0
  14. package/dist/_lazy-engine-boundary.js.map +1 -0
  15. package/dist/_lazy-math.js +13 -0
  16. package/dist/_lazy-math.js.map +1 -0
  17. package/dist/_lazy-mermaid.js +12 -0
  18. package/dist/_lazy-mermaid.js.map +1 -0
  19. package/dist/_mermaid-error-panel.js +9 -0
  20. package/dist/_mermaid-error-panel.js.map +1 -0
  21. package/dist/{_persona-rive-JEG44YHX.js → _persona-rive.js} +19 -24
  22. package/dist/_persona-rive.js.map +1 -0
  23. package/dist/_streamdown-i18n.js +21 -0
  24. package/dist/_streamdown-i18n.js.map +1 -0
  25. package/dist/_streamdown-safety.js +10 -0
  26. package/dist/_streamdown-safety.js.map +1 -0
  27. package/dist/_theme-scope-store.js +13 -0
  28. package/dist/_theme-scope-store.js.map +1 -0
  29. package/dist/a2ui/a2ui-surface.js +17 -0
  30. package/dist/a2ui/a2ui-surface.js.map +1 -0
  31. package/dist/a2ui/core/catalog.generated.js +10 -0
  32. package/dist/a2ui/core/catalog.generated.js.map +1 -0
  33. package/dist/a2ui/core/complete-json.js +10 -0
  34. package/dist/a2ui/core/complete-json.js.map +1 -0
  35. package/dist/a2ui/core/index.js +37 -0
  36. package/dist/a2ui/core/index.js.map +1 -0
  37. package/dist/a2ui/core/schema.js +11 -0
  38. package/dist/a2ui/core/schema.js.map +1 -0
  39. package/dist/a2ui/core/spec.js +10 -0
  40. package/dist/a2ui/core/spec.js.map +1 -0
  41. package/dist/a2ui/core/validate.js +16 -0
  42. package/dist/a2ui/core/validate.js.map +1 -0
  43. package/dist/a2ui/index.js +54 -0
  44. package/dist/a2ui/index.js.map +1 -0
  45. package/dist/a2ui/ui-catalog.js +18 -0
  46. package/dist/a2ui/ui-catalog.js.map +1 -0
  47. package/dist/agent-event.js +10 -0
  48. package/dist/agent-event.js.map +1 -0
  49. package/dist/agent-timeline.js +11 -0
  50. package/dist/agent-timeline.js.map +1 -0
  51. package/dist/agent.js +25 -0
  52. package/dist/agent.js.map +1 -0
  53. package/dist/artifact.js +23 -0
  54. package/dist/artifact.js.map +1 -0
  55. package/dist/asset-preview.js +22 -0
  56. package/dist/asset-preview.js.map +1 -0
  57. package/dist/attachments.js +33 -0
  58. package/dist/attachments.js.map +1 -0
  59. package/dist/audio-player.js +30 -0
  60. package/dist/audio-player.js.map +1 -0
  61. package/dist/audio-visualizer.js +9 -0
  62. package/dist/audio-visualizer.js.map +1 -0
  63. package/dist/canvas.js +10 -0
  64. package/dist/canvas.js.map +1 -0
  65. package/dist/chain-of-thought.js +22 -0
  66. package/dist/chain-of-thought.js.map +1 -0
  67. package/dist/chat-greeting.js +8 -0
  68. package/dist/chat-greeting.js.map +1 -0
  69. package/dist/chat-shell.js +9 -0
  70. package/dist/chat-shell.js.map +1 -0
  71. package/dist/checkpoint.js +13 -0
  72. package/dist/checkpoint.js.map +1 -0
  73. package/dist/chunk-2XOIG5TG.js +72 -0
  74. package/dist/chunk-2XOIG5TG.js.map +1 -0
  75. package/dist/chunk-34CQ2VHM.js +172 -0
  76. package/dist/chunk-34CQ2VHM.js.map +1 -0
  77. package/dist/chunk-3TDHPXZZ.js +60 -0
  78. package/dist/chunk-3TDHPXZZ.js.map +1 -0
  79. package/dist/chunk-3XNPMDZY.js +478 -0
  80. package/dist/chunk-3XNPMDZY.js.map +1 -0
  81. package/dist/chunk-3YPT3V7L.js +56 -0
  82. package/dist/chunk-3YPT3V7L.js.map +1 -0
  83. package/dist/chunk-475UEU2Q.js +87 -0
  84. package/dist/chunk-475UEU2Q.js.map +1 -0
  85. package/dist/chunk-4CBTII2I.js +95 -0
  86. package/dist/chunk-4CBTII2I.js.map +1 -0
  87. package/dist/chunk-4XRNIZMG.js +22 -0
  88. package/dist/chunk-4XRNIZMG.js.map +1 -0
  89. package/dist/chunk-5NNWUKK5.js +2 -0
  90. package/dist/chunk-5NNWUKK5.js.map +1 -0
  91. package/dist/chunk-5UOMU27Z.js +164 -0
  92. package/dist/chunk-5UOMU27Z.js.map +1 -0
  93. package/dist/chunk-5VGYZ62I.js +264 -0
  94. package/dist/chunk-5VGYZ62I.js.map +1 -0
  95. package/dist/chunk-6IQPH2OS.js +21 -0
  96. package/dist/chunk-6IQPH2OS.js.map +1 -0
  97. package/dist/chunk-6PB2MXCI.js +482 -0
  98. package/dist/chunk-6PB2MXCI.js.map +1 -0
  99. package/dist/chunk-7FD5CZEU.js +215 -0
  100. package/dist/chunk-7FD5CZEU.js.map +1 -0
  101. package/dist/chunk-7RL6KZDF.js +266 -0
  102. package/dist/chunk-7RL6KZDF.js.map +1 -0
  103. package/dist/chunk-ADOYAGGK.js +482 -0
  104. package/dist/chunk-ADOYAGGK.js.map +1 -0
  105. package/dist/chunk-AXMNJMMH.js +984 -0
  106. package/dist/chunk-AXMNJMMH.js.map +1 -0
  107. package/dist/chunk-BA3AEMOU.js +21 -0
  108. package/dist/chunk-BA3AEMOU.js.map +1 -0
  109. package/dist/chunk-BBHFOYML.js +336 -0
  110. package/dist/chunk-BBHFOYML.js.map +1 -0
  111. package/dist/chunk-BHUVISIY.js +221 -0
  112. package/dist/chunk-BHUVISIY.js.map +1 -0
  113. package/dist/chunk-BM2LWERA.js +100 -0
  114. package/dist/chunk-BM2LWERA.js.map +1 -0
  115. package/dist/chunk-CMOYXNPJ.js +211 -0
  116. package/dist/chunk-CMOYXNPJ.js.map +1 -0
  117. package/dist/chunk-CZP3RHC4.js +74 -0
  118. package/dist/chunk-CZP3RHC4.js.map +1 -0
  119. package/dist/chunk-DDG5JHQT.js +112 -0
  120. package/dist/chunk-DDG5JHQT.js.map +1 -0
  121. package/dist/chunk-DJODXO7I.js +38 -0
  122. package/dist/chunk-DJODXO7I.js.map +1 -0
  123. package/dist/chunk-DWJDJLPU.js +192 -0
  124. package/dist/chunk-DWJDJLPU.js.map +1 -0
  125. package/dist/chunk-DZW6LM22.js +45 -0
  126. package/dist/chunk-DZW6LM22.js.map +1 -0
  127. package/dist/chunk-ELGCZLZF.js +305 -0
  128. package/dist/chunk-ELGCZLZF.js.map +1 -0
  129. package/dist/chunk-EV3U6ZZB.js +209 -0
  130. package/dist/chunk-EV3U6ZZB.js.map +1 -0
  131. package/dist/chunk-EY7LVUKQ.js +87 -0
  132. package/dist/chunk-EY7LVUKQ.js.map +1 -0
  133. package/dist/chunk-F4C74F7M.js +230 -0
  134. package/dist/chunk-F4C74F7M.js.map +1 -0
  135. package/dist/chunk-FERYDFZA.js +108 -0
  136. package/dist/chunk-FERYDFZA.js.map +1 -0
  137. package/dist/chunk-FUIYG2DS.js +166 -0
  138. package/dist/chunk-FUIYG2DS.js.map +1 -0
  139. package/dist/chunk-GKYZT3LA.js +136 -0
  140. package/dist/chunk-GKYZT3LA.js.map +1 -0
  141. package/dist/chunk-H42LRUQ4.js +102 -0
  142. package/dist/chunk-H42LRUQ4.js.map +1 -0
  143. package/dist/chunk-HVXM2G5F.js +222 -0
  144. package/dist/chunk-HVXM2G5F.js.map +1 -0
  145. package/dist/chunk-I4RDAGVY.js +53 -0
  146. package/dist/chunk-I4RDAGVY.js.map +1 -0
  147. package/dist/chunk-IQJG4IDX.js +208 -0
  148. package/dist/chunk-IQJG4IDX.js.map +1 -0
  149. package/dist/chunk-IX2PXG4Y.js +144 -0
  150. package/dist/chunk-IX2PXG4Y.js.map +1 -0
  151. package/dist/chunk-IXICSOOP.js +287 -0
  152. package/dist/chunk-IXICSOOP.js.map +1 -0
  153. package/dist/chunk-JY5HSN4D.js +84 -0
  154. package/dist/chunk-JY5HSN4D.js.map +1 -0
  155. package/dist/chunk-LMNSBOBG.js +19 -0
  156. package/dist/chunk-LMNSBOBG.js.map +1 -0
  157. package/dist/chunk-MBI7D6IL.js +42 -0
  158. package/dist/chunk-MBI7D6IL.js.map +1 -0
  159. package/dist/chunk-MLFMYCPH.js +192 -0
  160. package/dist/chunk-MLFMYCPH.js.map +1 -0
  161. package/dist/chunk-MOK66734.js +33 -0
  162. package/dist/chunk-MOK66734.js.map +1 -0
  163. package/dist/chunk-MXTAWPYM.js +196 -0
  164. package/dist/chunk-MXTAWPYM.js.map +1 -0
  165. package/dist/chunk-NCL2UZKI.js +96 -0
  166. package/dist/chunk-NCL2UZKI.js.map +1 -0
  167. package/dist/chunk-NET4YLRY.js +107 -0
  168. package/dist/chunk-NET4YLRY.js.map +1 -0
  169. package/dist/chunk-NIG67CFM.js +329 -0
  170. package/dist/chunk-NIG67CFM.js.map +1 -0
  171. package/dist/chunk-NMVNNO3L.js +10 -0
  172. package/dist/chunk-NMVNNO3L.js.map +1 -0
  173. package/dist/chunk-NP7VID4K.js +2 -0
  174. package/dist/chunk-NP7VID4K.js.map +1 -0
  175. package/dist/chunk-NPUCMAG2.js +382 -0
  176. package/dist/chunk-NPUCMAG2.js.map +1 -0
  177. package/dist/chunk-NSCLRHES.js +102 -0
  178. package/dist/chunk-NSCLRHES.js.map +1 -0
  179. package/dist/chunk-OEUXHVFW.js +86 -0
  180. package/dist/chunk-OEUXHVFW.js.map +1 -0
  181. package/dist/chunk-ONBHFIMZ.js +137 -0
  182. package/dist/chunk-ONBHFIMZ.js.map +1 -0
  183. package/dist/chunk-OPH2HHL2.js +228 -0
  184. package/dist/chunk-OPH2HHL2.js.map +1 -0
  185. package/dist/chunk-OQERHIQP.js +287 -0
  186. package/dist/chunk-OQERHIQP.js.map +1 -0
  187. package/dist/chunk-P6YJAZFG.js +103 -0
  188. package/dist/chunk-P6YJAZFG.js.map +1 -0
  189. package/dist/chunk-PG7ERDOD.js +65 -0
  190. package/dist/chunk-PG7ERDOD.js.map +1 -0
  191. package/dist/chunk-PIB5JBMA.js +90 -0
  192. package/dist/chunk-PIB5JBMA.js.map +1 -0
  193. package/dist/chunk-PQ5BPIWQ.js +22 -0
  194. package/dist/chunk-PQ5BPIWQ.js.map +1 -0
  195. package/dist/chunk-PQBF6ZIQ.js +55 -0
  196. package/dist/chunk-PQBF6ZIQ.js.map +1 -0
  197. package/dist/chunk-PTWCTSZL.js +173 -0
  198. package/dist/chunk-PTWCTSZL.js.map +1 -0
  199. package/dist/chunk-QJUNPVOS.js +101 -0
  200. package/dist/chunk-QJUNPVOS.js.map +1 -0
  201. package/dist/chunk-QUDZOTRV.js +43 -0
  202. package/dist/chunk-QUDZOTRV.js.map +1 -0
  203. package/dist/chunk-RB7G65JC.js +213 -0
  204. package/dist/chunk-RB7G65JC.js.map +1 -0
  205. package/dist/chunk-RPHAOR7P.js +45 -0
  206. package/dist/chunk-RPHAOR7P.js.map +1 -0
  207. package/dist/chunk-RTCSH2AN.js +331 -0
  208. package/dist/chunk-RTCSH2AN.js.map +1 -0
  209. package/dist/chunk-S3ISPW3A.js +28 -0
  210. package/dist/chunk-S3ISPW3A.js.map +1 -0
  211. package/dist/chunk-SEVN656N.js +36 -0
  212. package/dist/chunk-SEVN656N.js.map +1 -0
  213. package/dist/chunk-SKVG672B.js +64 -0
  214. package/dist/chunk-SKVG672B.js.map +1 -0
  215. package/dist/chunk-SPQIU7GA.js +236 -0
  216. package/dist/chunk-SPQIU7GA.js.map +1 -0
  217. package/dist/chunk-SSGJ6MEM.js +1076 -0
  218. package/dist/chunk-SSGJ6MEM.js.map +1 -0
  219. package/dist/chunk-SSKZ2AED.js +118 -0
  220. package/dist/chunk-SSKZ2AED.js.map +1 -0
  221. package/dist/chunk-T56JFGXI.js +561 -0
  222. package/dist/chunk-T56JFGXI.js.map +1 -0
  223. package/dist/chunk-TCB6O74A.js +137 -0
  224. package/dist/chunk-TCB6O74A.js.map +1 -0
  225. package/dist/chunk-TTEYPO6X.js +57 -0
  226. package/dist/chunk-TTEYPO6X.js.map +1 -0
  227. package/dist/chunk-TWPHAJNM.js +462 -0
  228. package/dist/chunk-TWPHAJNM.js.map +1 -0
  229. package/dist/chunk-TXJJLP4O.js +336 -0
  230. package/dist/chunk-TXJJLP4O.js.map +1 -0
  231. package/dist/chunk-TZ6TB7VM.js +245 -0
  232. package/dist/chunk-TZ6TB7VM.js.map +1 -0
  233. package/dist/chunk-UBLKJJ7K.js +278 -0
  234. package/dist/chunk-UBLKJJ7K.js.map +1 -0
  235. package/dist/chunk-UCJ6IUFS.js +52 -0
  236. package/dist/chunk-UCJ6IUFS.js.map +1 -0
  237. package/dist/chunk-UCKFJ3QF.js +197 -0
  238. package/dist/chunk-UCKFJ3QF.js.map +1 -0
  239. package/dist/chunk-UPXSLILN.js +20 -0
  240. package/dist/chunk-UPXSLILN.js.map +1 -0
  241. package/dist/chunk-V4DORGWJ.js +92 -0
  242. package/dist/chunk-V4DORGWJ.js.map +1 -0
  243. package/dist/chunk-V6E5DYZD.js +80 -0
  244. package/dist/chunk-V6E5DYZD.js.map +1 -0
  245. package/dist/chunk-VLLYKF3P.js +96 -0
  246. package/dist/chunk-VLLYKF3P.js.map +1 -0
  247. package/dist/chunk-VLNBTOH6.js +43 -0
  248. package/dist/chunk-VLNBTOH6.js.map +1 -0
  249. package/dist/chunk-WMDSMSPL.js +303 -0
  250. package/dist/chunk-WMDSMSPL.js.map +1 -0
  251. package/dist/chunk-WU5BLGTF.js +149 -0
  252. package/dist/chunk-WU5BLGTF.js.map +1 -0
  253. package/dist/chunk-WYTZVSGK.js +245 -0
  254. package/dist/chunk-WYTZVSGK.js.map +1 -0
  255. package/dist/chunk-X47QMM6K.js +187 -0
  256. package/dist/chunk-X47QMM6K.js.map +1 -0
  257. package/dist/chunk-XNBKO32Y.js +174 -0
  258. package/dist/chunk-XNBKO32Y.js.map +1 -0
  259. package/dist/chunk-YHUSW7D2.js +40 -0
  260. package/dist/chunk-YHUSW7D2.js.map +1 -0
  261. package/dist/chunk-YSKD7UXX.js +126 -0
  262. package/dist/chunk-YSKD7UXX.js.map +1 -0
  263. package/dist/chunk-YYRDGWOU.js +72 -0
  264. package/dist/chunk-YYRDGWOU.js.map +1 -0
  265. package/dist/chunk-ZIGZMWM7.js +19 -0
  266. package/dist/chunk-ZIGZMWM7.js.map +1 -0
  267. package/dist/chunk-ZKRTUKNP.js +40 -0
  268. package/dist/chunk-ZKRTUKNP.js.map +1 -0
  269. package/dist/code-block.js +38 -0
  270. package/dist/code-block.js.map +1 -0
  271. package/dist/commit.js +51 -0
  272. package/dist/commit.js.map +1 -0
  273. package/dist/composer.js +15 -0
  274. package/dist/composer.js.map +1 -0
  275. package/dist/confirmation.js +53 -0
  276. package/dist/confirmation.js.map +1 -0
  277. package/dist/connection.js +8 -0
  278. package/dist/connection.js.map +1 -0
  279. package/dist/context-panel.js +25 -0
  280. package/dist/context-panel.js.map +1 -0
  281. package/dist/controls.js +10 -0
  282. package/dist/controls.js.map +1 -0
  283. package/dist/conversation.js +19 -0
  284. package/dist/conversation.js.map +1 -0
  285. package/dist/diff-view.js +15 -0
  286. package/dist/diff-view.js.map +1 -0
  287. package/dist/edge.js +10 -0
  288. package/dist/edge.js.map +1 -0
  289. package/dist/environment-variables.js +29 -0
  290. package/dist/environment-variables.js.map +1 -0
  291. package/dist/file-tree.js +23 -0
  292. package/dist/file-tree.js.map +1 -0
  293. package/dist/gallery.js +9 -0
  294. package/dist/gallery.js.map +1 -0
  295. package/dist/grouped-parts.js +21 -0
  296. package/dist/grouped-parts.js.map +1 -0
  297. package/dist/image.js +9 -0
  298. package/dist/image.js.map +1 -0
  299. package/dist/index.d.ts +366 -98
  300. package/dist/index.js +672 -13577
  301. package/dist/index.js.map +1 -1
  302. package/dist/inline-citation.js +39 -0
  303. package/dist/inline-citation.js.map +1 -0
  304. package/dist/jsx-preview.js +17 -0
  305. package/dist/jsx-preview.js.map +1 -0
  306. package/dist/markdown-view.js +17 -0
  307. package/dist/markdown-view.js.map +1 -0
  308. package/dist/message-compare.js +12 -0
  309. package/dist/message-compare.js.map +1 -0
  310. package/dist/message-edit.js +19 -0
  311. package/dist/message-edit.js.map +1 -0
  312. package/dist/message-feedback.js +11 -0
  313. package/dist/message-feedback.js.map +1 -0
  314. package/dist/message-form-spec.js +38 -0
  315. package/dist/message-form-spec.js.map +1 -0
  316. package/dist/message-form.js +26 -0
  317. package/dist/message-form.js.map +1 -0
  318. package/dist/message-table-spec.js +26 -0
  319. package/dist/message-table-spec.js.map +1 -0
  320. package/dist/message-table.js +12 -0
  321. package/dist/message-table.js.map +1 -0
  322. package/dist/message.js +51 -0
  323. package/dist/message.js.map +1 -0
  324. package/dist/mic-selector.js +27 -0
  325. package/dist/mic-selector.js.map +1 -0
  326. package/dist/model-provider-logo.js +13 -0
  327. package/dist/model-provider-logo.js.map +1 -0
  328. package/dist/motion-config.js +9 -0
  329. package/dist/motion-config.js.map +1 -0
  330. package/dist/node.js +22 -0
  331. package/dist/node.js.map +1 -0
  332. package/dist/open-in-chat.js +31 -0
  333. package/dist/open-in-chat.js.map +1 -0
  334. package/dist/package-info.js +25 -0
  335. package/dist/package-info.js.map +1 -0
  336. package/dist/panel.js +10 -0
  337. package/dist/panel.js.map +1 -0
  338. package/dist/part-groups.js +18 -0
  339. package/dist/part-groups.js.map +1 -0
  340. package/dist/permission-mode-select.js +9 -0
  341. package/dist/permission-mode-select.js.map +1 -0
  342. package/dist/persona-sources.js +8 -0
  343. package/dist/persona-sources.js.map +1 -0
  344. package/dist/persona.js +14 -0
  345. package/dist/persona.js.map +1 -0
  346. package/dist/plan.js +32 -0
  347. package/dist/plan.js.map +1 -0
  348. package/dist/prompt-input-effort.js +9 -0
  349. package/dist/prompt-input-effort.js.map +1 -0
  350. package/dist/prompt-input-mode.js +10 -0
  351. package/dist/prompt-input-mode.js.map +1 -0
  352. package/dist/prompt-input-slash.js +12 -0
  353. package/dist/prompt-input-slash.js.map +1 -0
  354. package/dist/prompt-input.js +89 -0
  355. package/dist/prompt-input.js.map +1 -0
  356. package/dist/queue.js +37 -0
  357. package/dist/queue.js.map +1 -0
  358. package/dist/reasoning.js +23 -0
  359. package/dist/reasoning.js.map +1 -0
  360. package/dist/sandbox.js +28 -0
  361. package/dist/sandbox.js.map +1 -0
  362. package/dist/schema-display.js +33 -0
  363. package/dist/schema-display.js.map +1 -0
  364. package/dist/selection-toolbar.js +11 -0
  365. package/dist/selection-toolbar.js.map +1 -0
  366. package/dist/session-header.js +9 -0
  367. package/dist/session-header.js.map +1 -0
  368. package/dist/session-status-bar.js +9 -0
  369. package/dist/session-status-bar.js.map +1 -0
  370. package/dist/shimmer.js +9 -0
  371. package/dist/shimmer.js.map +1 -0
  372. package/dist/snippet.js +17 -0
  373. package/dist/snippet.js.map +1 -0
  374. package/dist/sources.js +17 -0
  375. package/dist/sources.js.map +1 -0
  376. package/dist/speech-input.js +9 -0
  377. package/dist/speech-input.js.map +1 -0
  378. package/dist/stack-trace.js +27 -0
  379. package/dist/stack-trace.js.map +1 -0
  380. package/dist/suggestion.js +16 -0
  381. package/dist/suggestion.js.map +1 -0
  382. package/dist/task.js +18 -0
  383. package/dist/task.js.map +1 -0
  384. package/dist/test-results.js +43 -0
  385. package/dist/test-results.js.map +1 -0
  386. package/dist/token-usage.js +27 -0
  387. package/dist/token-usage.js.map +1 -0
  388. package/dist/tool-result-card.js +9 -0
  389. package/dist/tool-result-card.js.map +1 -0
  390. package/dist/tool.js +27 -0
  391. package/dist/tool.js.map +1 -0
  392. package/dist/toolbar.js +10 -0
  393. package/dist/toolbar.js.map +1 -0
  394. package/dist/transcription.js +11 -0
  395. package/dist/transcription.js.map +1 -0
  396. package/dist/turn-status.js +9 -0
  397. package/dist/turn-status.js.map +1 -0
  398. package/dist/use-audio-level.js +9 -0
  399. package/dist/use-audio-level.js.map +1 -0
  400. package/dist/voice-selector.js +47 -0
  401. package/dist/voice-selector.js.map +1 -0
  402. package/dist/web-preview.js +19 -0
  403. package/dist/web-preview.js.map +1 -0
  404. package/package.json +11 -9
  405. package/schemas/a2ui-surface.v1.schema.json +5425 -0
  406. package/src/_chat-shell-rail.tsx +3 -1
  407. package/src/_flow-boundary.tsx +2 -2
  408. package/src/_persona-rive.tsx +27 -41
  409. package/src/a2ui/a2ui-surface.stories.tsx +662 -0
  410. package/src/a2ui/a2ui-surface.test.tsx +201 -0
  411. package/src/a2ui/a2ui-surface.tsx +354 -0
  412. package/src/a2ui/catalog.source.json +772 -0
  413. package/src/a2ui/core/a2ui-core.test.ts +178 -0
  414. package/src/a2ui/core/catalog.generated.ts +1006 -0
  415. package/src/a2ui/core/complete-json.ts +81 -0
  416. package/src/a2ui/core/index.ts +10 -0
  417. package/src/a2ui/core/schema.ts +111 -0
  418. package/src/a2ui/core/spec.ts +148 -0
  419. package/src/a2ui/core/validate.ts +266 -0
  420. package/src/a2ui/index.ts +7 -0
  421. package/src/a2ui/ui-catalog.tsx +225 -0
  422. package/src/a2ui/wave1-chart-spec.test.ts +87 -0
  423. package/src/a2ui/wave2-chart-spec.test.ts +108 -0
  424. package/src/agentic-workspace.stories.tsx +6 -45
  425. package/src/chat-shell.test.tsx +40 -10
  426. package/src/chat-shell.tsx +90 -44
  427. package/src/chat.stories.tsx +47 -42
  428. package/src/composer.stories.tsx +4 -5
  429. package/src/composer.test.tsx +45 -0
  430. package/src/composer.tsx +104 -21
  431. package/src/context-panel.stories.tsx +1 -1
  432. package/src/context-panel.tsx +1 -1
  433. package/src/conversation.stories.tsx +1 -0
  434. package/src/conversation.test.tsx +16 -0
  435. package/src/conversation.tsx +16 -2
  436. package/src/diff-view.stories.tsx +79 -0
  437. package/src/diff-view.tsx +3 -2
  438. package/src/file-tree.tsx +24 -17
  439. package/src/gallery.stories.tsx +42 -0
  440. package/src/gallery.tsx +2 -2
  441. package/src/grouped-parts.stories.tsx +23 -0
  442. package/src/grouped-parts.tsx +1 -1
  443. package/src/index.ts +1 -0
  444. package/src/message-compare.stories.tsx +40 -0
  445. package/src/message-compare.tsx +2 -1
  446. package/src/message-form.tsx +1 -1
  447. package/src/message-table.stories.tsx +24 -0
  448. package/src/message-table.tsx +1 -1
  449. package/src/package-info.tsx +12 -9
  450. package/src/reasoning.stories.tsx +27 -0
  451. package/src/reasoning.tsx +1 -1
  452. package/src/session-header.stories.tsx +35 -1
  453. package/src/session-header.tsx +1 -1
  454. package/src/sources.stories.tsx +30 -0
  455. package/src/sources.tsx +4 -1
  456. package/src/templates-ai-assistant.stories.tsx +151 -87
  457. package/src/tool.stories.tsx +39 -0
  458. package/src/tool.tsx +3 -3
  459. package/src/toolbar.tsx +0 -10
  460. package/dist/_flow-boundary-SHNWLQG5.js.map +0 -1
  461. package/dist/_persona-rive-JEG44YHX.js.map +0 -1
  462. /package/dist/{_audio-player-media-chrome-T3XVXWRZ.js.map → _audio-player-media-chrome.js.map} +0 -0
@@ -0,0 +1,74 @@
1
+ "use client";
2
+ import {
3
+ CodeBlock
4
+ } from "./chunk-TWPHAJNM.js";
5
+
6
+ // src/agent.tsx
7
+ import {
8
+ Accordion,
9
+ AccordionContent,
10
+ AccordionItem,
11
+ AccordionTrigger
12
+ } from "@elabs-ai/components-ui";
13
+ import { Badge } from "@elabs-ai/components-ui";
14
+ import { useLocale } from "@elabs-ai/components-ui";
15
+ import { cn } from "@elabs-ai/components-ui/lib/cn";
16
+ import { BotIcon } from "lucide-react";
17
+ import { memo } from "react";
18
+ import { jsx, jsxs } from "react/jsx-runtime";
19
+ var Agent = memo(({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("not-prose w-full rounded-md border", className), ...props }));
20
+ var AgentHeader = memo(({ className, name, model, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex w-full items-center justify-between gap-4 p-3", className), ...props, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
21
+ /* @__PURE__ */ jsx(BotIcon, { className: "size-4 text-muted-foreground" }),
22
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-body", children: name }),
23
+ model && /* @__PURE__ */ jsx(Badge, { className: "font-mono text-meta", variant: "secondary", children: model })
24
+ ] }) }));
25
+ var AgentContent = memo(({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("space-y-4 p-4 pt-0", className), ...props }));
26
+ var AgentInstructions = memo(
27
+ ({ className, children, ...props }) => {
28
+ const { t } = useLocale();
29
+ return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", className), ...props, children: [
30
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground text-body", children: t("ai.agent.instructions") }),
31
+ /* @__PURE__ */ jsx("div", { className: "rounded-md bg-muted/50 p-3 text-muted-foreground text-body", children: /* @__PURE__ */ jsx("p", { children }) })
32
+ ] });
33
+ }
34
+ );
35
+ var AgentTools = memo(({ className, ...props }) => {
36
+ const { t } = useLocale();
37
+ return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", className), children: [
38
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground text-body", children: t("ai.agent.tools") }),
39
+ /* @__PURE__ */ jsx(Accordion, { className: "rounded-md border", ...props })
40
+ ] });
41
+ });
42
+ var AgentTool = memo(({ className, tool, value, ...props }) => {
43
+ const schema = "jsonSchema" in tool && tool.jsonSchema ? tool.jsonSchema : tool.inputSchema;
44
+ const description = typeof tool.description === "string" ? tool.description : void 0;
45
+ return /* @__PURE__ */ jsxs(AccordionItem, { className: cn("border-b last:border-b-0", className), value, ...props, children: [
46
+ /* @__PURE__ */ jsx(AccordionTrigger, { className: "px-3 py-2 text-body hover:no-underline", children: description ?? "No description" }),
47
+ /* @__PURE__ */ jsx(AccordionContent, { className: "px-3 pb-3", children: /* @__PURE__ */ jsx("div", { className: "rounded-md bg-muted/50", children: /* @__PURE__ */ jsx(CodeBlock, { code: JSON.stringify(schema, null, 2), language: "json" }) }) })
48
+ ] });
49
+ });
50
+ var AgentOutput = memo(({ className, schema, ...props }) => {
51
+ const { t } = useLocale();
52
+ return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", className), ...props, children: [
53
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground text-body", children: t("ai.agent.outputSchema") }),
54
+ /* @__PURE__ */ jsx("div", { className: "rounded-md bg-muted/50", children: /* @__PURE__ */ jsx(CodeBlock, { code: schema, language: "typescript" }) })
55
+ ] });
56
+ });
57
+ Agent.displayName = "Agent";
58
+ AgentHeader.displayName = "AgentHeader";
59
+ AgentContent.displayName = "AgentContent";
60
+ AgentInstructions.displayName = "AgentInstructions";
61
+ AgentTools.displayName = "AgentTools";
62
+ AgentTool.displayName = "AgentTool";
63
+ AgentOutput.displayName = "AgentOutput";
64
+
65
+ export {
66
+ Agent,
67
+ AgentHeader,
68
+ AgentContent,
69
+ AgentInstructions,
70
+ AgentTools,
71
+ AgentTool,
72
+ AgentOutput
73
+ };
74
+ //# sourceMappingURL=chunk-CZP3RHC4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agent.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from \"@elabs-ai/components-ui\";\nimport { Badge } from \"@elabs-ai/components-ui\";\nimport { useLocale } from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport type { Tool } from \"ai\";\nimport { BotIcon } from \"lucide-react\";\nimport type { ComponentProps } from \"react\";\nimport { memo } from \"react\";\n\nimport { CodeBlock } from \"./code-block\";\n\nexport type AgentProps = ComponentProps<\"div\">;\n\nexport const Agent = memo(({ className, ...props }: AgentProps) => (\n <div className={cn(\"not-prose w-full rounded-md border\", className)} {...props} />\n));\n\nexport type AgentHeaderProps = ComponentProps<\"div\"> & {\n name: string;\n model?: string;\n};\n\nexport const AgentHeader = memo(({ className, name, model, ...props }: AgentHeaderProps) => (\n <div className={cn(\"flex w-full items-center justify-between gap-4 p-3\", className)} {...props}>\n <div className=\"flex items-center gap-2\">\n <BotIcon className=\"size-4 text-muted-foreground\" />\n <span className=\"font-medium text-body\">{name}</span>\n {model && (\n <Badge className=\"font-mono text-meta\" variant=\"secondary\">\n {model}\n </Badge>\n )}\n </div>\n </div>\n));\n\nexport type AgentContentProps = ComponentProps<\"div\">;\n\nexport const AgentContent = memo(({ className, ...props }: AgentContentProps) => (\n <div className={cn(\"space-y-4 p-4 pt-0\", className)} {...props} />\n));\n\nexport type AgentInstructionsProps = ComponentProps<\"div\"> & {\n children: string;\n};\n\nexport const AgentInstructions = memo(\n ({ className, children, ...props }: AgentInstructionsProps) => {\n const { t } = useLocale();\n return (\n <div className={cn(\"space-y-2\", className)} {...props}>\n <span className=\"font-medium text-muted-foreground text-body\">\n {t(\"ai.agent.instructions\")}\n </span>\n <div className=\"rounded-md bg-muted/50 p-3 text-muted-foreground text-body\">\n <p>{children}</p>\n </div>\n </div>\n );\n },\n);\n\nexport type AgentToolsProps = ComponentProps<typeof Accordion>;\n\nexport const AgentTools = memo(({ className, ...props }: AgentToolsProps) => {\n const { t } = useLocale();\n return (\n <div className={cn(\"space-y-2\", className)}>\n <span className=\"font-medium text-muted-foreground text-body\">{t(\"ai.agent.tools\")}</span>\n <Accordion className=\"rounded-md border\" {...props} />\n </div>\n );\n});\n\nexport type AgentToolProps = ComponentProps<typeof AccordionItem> & {\n tool: Tool;\n};\n\nexport const AgentTool = memo(({ className, tool, value, ...props }: AgentToolProps) => {\n const schema = \"jsonSchema\" in tool && tool.jsonSchema ? tool.jsonSchema : tool.inputSchema;\n // `tool.description` may be a fixed string OR (ai@7+) a function of the live\n // call context (`(options) => string`) for a per-call dynamic description.\n // AgentTool renders a static list, so it has no call context to invoke that\n // function with — show it only when it is already a plain string.\n const description = typeof tool.description === \"string\" ? tool.description : undefined;\n\n return (\n <AccordionItem className={cn(\"border-b last:border-b-0\", className)} value={value} {...props}>\n <AccordionTrigger className=\"px-3 py-2 text-body hover:no-underline\">\n {description ?? \"No description\"}\n </AccordionTrigger>\n <AccordionContent className=\"px-3 pb-3\">\n <div className=\"rounded-md bg-muted/50\">\n <CodeBlock code={JSON.stringify(schema, null, 2)} language=\"json\" />\n </div>\n </AccordionContent>\n </AccordionItem>\n );\n});\n\nexport type AgentOutputProps = ComponentProps<\"div\"> & {\n schema: string;\n};\n\nexport const AgentOutput = memo(({ className, schema, ...props }: AgentOutputProps) => {\n const { t } = useLocale();\n return (\n <div className={cn(\"space-y-2\", className)} {...props}>\n <span className=\"font-medium text-muted-foreground text-body\">\n {t(\"ai.agent.outputSchema\")}\n </span>\n <div className=\"rounded-md bg-muted/50\">\n <CodeBlock code={schema} language=\"typescript\" />\n </div>\n </div>\n );\n});\n\nAgent.displayName = \"Agent\";\nAgentHeader.displayName = \"AgentHeader\";\nAgentContent.displayName = \"AgentContent\";\nAgentInstructions.displayName = \"AgentInstructions\";\nAgentTools.displayName = \"AgentTools\";\nAgentTool.displayName = \"AgentTool\";\nAgentOutput.displayName = \"AgentOutput\";\n"],"mappings":";;;;;;AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,iBAAiB;AAC1B,SAAS,UAAU;AAEnB,SAAS,eAAe;AAExB,SAAS,YAAY;AAOnB,cAUE,YAVF;AADK,IAAM,QAAQ,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,MAC/C,oBAAC,SAAI,WAAW,GAAG,sCAAsC,SAAS,GAAI,GAAG,OAAO,CACjF;AAOM,IAAM,cAAc,KAAK,CAAC,EAAE,WAAW,MAAM,OAAO,GAAG,MAAM,MAClE,oBAAC,SAAI,WAAW,GAAG,sDAAsD,SAAS,GAAI,GAAG,OACvF,+BAAC,SAAI,WAAU,2BACb;AAAA,sBAAC,WAAQ,WAAU,gCAA+B;AAAA,EAClD,oBAAC,UAAK,WAAU,yBAAyB,gBAAK;AAAA,EAC7C,SACC,oBAAC,SAAM,WAAU,uBAAsB,SAAQ,aAC5C,iBACH;AAAA,GAEJ,GACF,CACD;AAIM,IAAM,eAAe,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,MACtD,oBAAC,SAAI,WAAW,GAAG,sBAAsB,SAAS,GAAI,GAAG,OAAO,CACjE;AAMM,IAAM,oBAAoB;AAAA,EAC/B,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,MAA8B;AAC7D,UAAM,EAAE,EAAE,IAAI,UAAU;AACxB,WACE,qBAAC,SAAI,WAAW,GAAG,aAAa,SAAS,GAAI,GAAG,OAC9C;AAAA,0BAAC,UAAK,WAAU,+CACb,YAAE,uBAAuB,GAC5B;AAAA,MACA,oBAAC,SAAI,WAAU,8DACb,8BAAC,OAAG,UAAS,GACf;AAAA,OACF;AAAA,EAEJ;AACF;AAIO,IAAM,aAAa,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,MAAuB;AAC3E,QAAM,EAAE,EAAE,IAAI,UAAU;AACxB,SACE,qBAAC,SAAI,WAAW,GAAG,aAAa,SAAS,GACvC;AAAA,wBAAC,UAAK,WAAU,+CAA+C,YAAE,gBAAgB,GAAE;AAAA,IACnF,oBAAC,aAAU,WAAU,qBAAqB,GAAG,OAAO;AAAA,KACtD;AAEJ,CAAC;AAMM,IAAM,YAAY,KAAK,CAAC,EAAE,WAAW,MAAM,OAAO,GAAG,MAAM,MAAsB;AACtF,QAAM,SAAS,gBAAgB,QAAQ,KAAK,aAAa,KAAK,aAAa,KAAK;AAKhF,QAAM,cAAc,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc;AAE9E,SACE,qBAAC,iBAAc,WAAW,GAAG,4BAA4B,SAAS,GAAG,OAAe,GAAG,OACrF;AAAA,wBAAC,oBAAiB,WAAU,0CACzB,yBAAe,kBAClB;AAAA,IACA,oBAAC,oBAAiB,WAAU,aAC1B,8BAAC,SAAI,WAAU,0BACb,8BAAC,aAAU,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,UAAS,QAAO,GACpE,GACF;AAAA,KACF;AAEJ,CAAC;AAMM,IAAM,cAAc,KAAK,CAAC,EAAE,WAAW,QAAQ,GAAG,MAAM,MAAwB;AACrF,QAAM,EAAE,EAAE,IAAI,UAAU;AACxB,SACE,qBAAC,SAAI,WAAW,GAAG,aAAa,SAAS,GAAI,GAAG,OAC9C;AAAA,wBAAC,UAAK,WAAU,+CACb,YAAE,uBAAuB,GAC5B;AAAA,IACA,oBAAC,SAAI,WAAU,0BACb,8BAAC,aAAU,MAAM,QAAQ,UAAS,cAAa,GACjD;AAAA,KACF;AAEJ,CAAC;AAED,MAAM,cAAc;AACpB,YAAY,cAAc;AAC1B,aAAa,cAAc;AAC3B,kBAAkB,cAAc;AAChC,WAAW,cAAc;AACzB,UAAU,cAAc;AACxB,YAAY,cAAc;","names":[]}
@@ -0,0 +1,112 @@
1
+ "use client";
2
+
3
+ // src/artifact.tsx
4
+ import { Button, Skeleton, useLocale } from "@elabs-ai/components-ui";
5
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@elabs-ai/components-ui";
6
+ import { cn } from "@elabs-ai/components-ui/lib/cn";
7
+ import { XIcon } from "lucide-react";
8
+ import { createContext, use, useMemo } from "react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ var ArtifactContext = createContext({ loading: false });
11
+ var Artifact = ({ className, loading = false, children, ...props }) => {
12
+ const contextValue = useMemo(() => ({ loading }), [loading]);
13
+ return /* @__PURE__ */ jsx(ArtifactContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
14
+ "div",
15
+ {
16
+ className: cn(
17
+ "flex flex-col overflow-hidden rounded-lg border bg-background shadow-sm",
18
+ className
19
+ ),
20
+ ...props,
21
+ children
22
+ }
23
+ ) });
24
+ };
25
+ var ArtifactHeader = ({ className, ...props }) => /* @__PURE__ */ jsx(
26
+ "div",
27
+ {
28
+ className: cn("flex items-center justify-between border-b bg-muted/50 px-4 py-3", className),
29
+ ...props
30
+ }
31
+ );
32
+ var ArtifactClose = ({
33
+ className,
34
+ children,
35
+ size = "sm",
36
+ variant = "ghost",
37
+ ...props
38
+ }) => {
39
+ const { t } = useLocale();
40
+ return /* @__PURE__ */ jsxs(
41
+ Button,
42
+ {
43
+ className: cn("size-8 p-0 text-muted-foreground hover:text-foreground", className),
44
+ size,
45
+ type: "button",
46
+ variant,
47
+ ...props,
48
+ children: [
49
+ children ?? /* @__PURE__ */ jsx(XIcon, { className: "size-4" }),
50
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("close") })
51
+ ]
52
+ }
53
+ );
54
+ };
55
+ var ArtifactTitle = ({ className, ...props }) => /* @__PURE__ */ jsx("p", { className: cn("font-medium text-foreground text-body", className), ...props });
56
+ var ArtifactDescription = ({ className, ...props }) => /* @__PURE__ */ jsx("p", { className: cn("text-muted-foreground text-body", className), ...props });
57
+ var ArtifactActions = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-1", className), ...props });
58
+ var ArtifactAction = ({
59
+ tooltip,
60
+ label,
61
+ icon: Icon,
62
+ children,
63
+ className,
64
+ size = "sm",
65
+ variant = "ghost",
66
+ ...props
67
+ }) => {
68
+ const button = /* @__PURE__ */ jsxs(
69
+ Button,
70
+ {
71
+ className: cn("size-8 p-0 text-muted-foreground hover:text-foreground", className),
72
+ size,
73
+ type: "button",
74
+ variant,
75
+ ...props,
76
+ children: [
77
+ Icon ? /* @__PURE__ */ jsx(Icon, { className: "size-4" }) : children,
78
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: label || tooltip })
79
+ ]
80
+ }
81
+ );
82
+ if (tooltip) {
83
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
84
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: button }),
85
+ /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("p", { children: tooltip }) })
86
+ ] }) });
87
+ }
88
+ return button;
89
+ };
90
+ var ArtifactContent = ({ className, children, ...props }) => {
91
+ const { loading } = use(ArtifactContext);
92
+ const { t } = useLocale();
93
+ return /* @__PURE__ */ jsx("div", { className: cn("flex-1 overflow-auto p-4", className), ...props, children: loading ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", role: "status", "aria-live": "polite", children: [
94
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("loading") }),
95
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-3/4" }),
96
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }),
97
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-5/6" }),
98
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-1/2" })
99
+ ] }) : children });
100
+ };
101
+
102
+ export {
103
+ Artifact,
104
+ ArtifactHeader,
105
+ ArtifactClose,
106
+ ArtifactTitle,
107
+ ArtifactDescription,
108
+ ArtifactActions,
109
+ ArtifactAction,
110
+ ArtifactContent
111
+ };
112
+ //# sourceMappingURL=chunk-DDG5JHQT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/artifact.tsx"],"sourcesContent":["\"use client\";\n\nimport { Button, Skeleton, useLocale } from \"@elabs-ai/components-ui\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport type { LucideIcon } from \"lucide-react\";\nimport { XIcon } from \"lucide-react\";\nimport type { ComponentProps, HTMLAttributes } from \"react\";\nimport { createContext, use, useMemo } from \"react\";\n\n/**\n * Shared `loading` state (composition-patterns — lifted into the provider):\n * `Artifact` is the ONLY place that knows whether the body has arrived;\n * `ArtifactContent` reads the interface and renders its skeleton, while\n * `ArtifactHeader`/`ArtifactTitle` (ordinary children of `Artifact`) keep\n * rendering normally, untouched by the not-ready state.\n */\nconst ArtifactContext = createContext<{ loading: boolean }>({ loading: false });\n\nexport type ArtifactProps = HTMLAttributes<HTMLDivElement> & {\n /**\n * The artifact body has not arrived yet (loading-states.md loading signal).\n * ArtifactContent renders a layout-shaped skeleton instead of its\n * children; ArtifactHeader/ArtifactTitle keep rendering as passed.\n * @default false\n */\n loading?: boolean;\n};\n\nexport const Artifact = ({ className, loading = false, children, ...props }: ArtifactProps) => {\n const contextValue = useMemo(() => ({ loading }), [loading]);\n\n return (\n <ArtifactContext.Provider value={contextValue}>\n <div\n // KEEP this border (#194, research 08 §G.5): it is redundant on light\n // (the #187 page-ground recess + shadow already lift the frame), but under\n // high decoration the shadow is zeroed and the border becomes the\n // SOLE structural cue — the canonical \"redundant-on-light, sole-cue-under-\n // decoration\" KEEP example. Do not drop it in a border-noise pass.\n className={cn(\n \"flex flex-col overflow-hidden rounded-lg border bg-background shadow-sm\",\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </ArtifactContext.Provider>\n );\n};\n\nexport type ArtifactHeaderProps = HTMLAttributes<HTMLDivElement>;\n\nexport const ArtifactHeader = ({ className, ...props }: ArtifactHeaderProps) => (\n <div\n className={cn(\"flex items-center justify-between border-b bg-muted/50 px-4 py-3\", className)}\n {...props}\n />\n);\n\nexport type ArtifactCloseProps = ComponentProps<typeof Button>;\n\nexport const ArtifactClose = ({\n className,\n children,\n size = \"sm\",\n variant = \"ghost\",\n ...props\n}: ArtifactCloseProps) => {\n const { t } = useLocale();\n return (\n <Button\n className={cn(\"size-8 p-0 text-muted-foreground hover:text-foreground\", className)}\n size={size}\n type=\"button\"\n variant={variant}\n {...props}\n >\n {children ?? <XIcon className=\"size-4\" />}\n <span className=\"sr-only\">{t(\"close\")}</span>\n </Button>\n );\n};\n\nexport type ArtifactTitleProps = HTMLAttributes<HTMLParagraphElement>;\n\nexport const ArtifactTitle = ({ className, ...props }: ArtifactTitleProps) => (\n <p className={cn(\"font-medium text-foreground text-body\", className)} {...props} />\n);\n\nexport type ArtifactDescriptionProps = HTMLAttributes<HTMLParagraphElement>;\n\nexport const ArtifactDescription = ({ className, ...props }: ArtifactDescriptionProps) => (\n <p className={cn(\"text-muted-foreground text-body\", className)} {...props} />\n);\n\nexport type ArtifactActionsProps = HTMLAttributes<HTMLDivElement>;\n\nexport const ArtifactActions = ({ className, ...props }: ArtifactActionsProps) => (\n <div className={cn(\"flex items-center gap-1\", className)} {...props} />\n);\n\nexport type ArtifactActionProps = ComponentProps<typeof Button> & {\n tooltip?: string;\n label?: string;\n icon?: LucideIcon;\n};\n\nexport const ArtifactAction = ({\n tooltip,\n label,\n icon: Icon,\n children,\n className,\n size = \"sm\",\n variant = \"ghost\",\n ...props\n}: ArtifactActionProps) => {\n const button = (\n <Button\n className={cn(\"size-8 p-0 text-muted-foreground hover:text-foreground\", className)}\n size={size}\n type=\"button\"\n variant={variant}\n {...props}\n >\n {Icon ? <Icon className=\"size-4\" /> : children}\n <span className=\"sr-only\">{label || tooltip}</span>\n </Button>\n );\n\n if (tooltip) {\n return (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>{button}</TooltipTrigger>\n <TooltipContent>\n <p>{tooltip}</p>\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n }\n\n return button;\n};\n\nexport type ArtifactContentProps = HTMLAttributes<HTMLDivElement>;\n\nexport const ArtifactContent = ({ className, children, ...props }: ArtifactContentProps) => {\n const { loading } = use(ArtifactContext);\n const { t } = useLocale();\n\n return (\n <div className={cn(\"flex-1 overflow-auto p-4\", className)} {...props}>\n {loading ? (\n <div className=\"space-y-2\" role=\"status\" aria-live=\"polite\">\n <span className=\"sr-only\">{t(\"loading\")}</span>\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-5/6\" />\n <Skeleton className=\"h-4 w-1/2\" />\n </div>\n ) : (\n children\n )}\n </div>\n );\n};\n"],"mappings":"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","names":[]}
@@ -0,0 +1,38 @@
1
+ "use client";
2
+
3
+ // src/checkpoint.tsx
4
+ import { Button } from "@elabs-ai/components-ui";
5
+ import { Separator } from "@elabs-ai/components-ui";
6
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@elabs-ai/components-ui";
7
+ import { cn } from "@elabs-ai/components-ui/lib/cn";
8
+ import { BookmarkIcon } from "lucide-react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ var Checkpoint = ({ className, children, ...props }) => /* @__PURE__ */ jsxs(
11
+ "div",
12
+ {
13
+ className: cn("flex items-center gap-0.5 overflow-hidden text-muted-foreground", className),
14
+ ...props,
15
+ children: [
16
+ children,
17
+ /* @__PURE__ */ jsx(Separator, {})
18
+ ]
19
+ }
20
+ );
21
+ var CheckpointIcon = ({ className, children, ...props }) => children ?? /* @__PURE__ */ jsx(BookmarkIcon, { className: cn("size-4 shrink-0", className), ...props });
22
+ var CheckpointTrigger = ({
23
+ children,
24
+ variant = "ghost",
25
+ size = "sm",
26
+ tooltip,
27
+ ...props
28
+ }) => tooltip ? /* @__PURE__ */ jsxs(Tooltip, { children: [
29
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size, type: "button", variant, ...props, children }) }),
30
+ /* @__PURE__ */ jsx(TooltipContent, { align: "start", side: "bottom", children: tooltip })
31
+ ] }) : /* @__PURE__ */ jsx(Button, { size, type: "button", variant, ...props, children });
32
+
33
+ export {
34
+ Checkpoint,
35
+ CheckpointIcon,
36
+ CheckpointTrigger
37
+ };
38
+ //# sourceMappingURL=chunk-DJODXO7I.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/checkpoint.tsx"],"sourcesContent":["\"use client\";\n\nimport { Button } from \"@elabs-ai/components-ui\";\nimport { Separator } from \"@elabs-ai/components-ui\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport type { LucideProps } from \"lucide-react\";\nimport { BookmarkIcon } from \"lucide-react\";\nimport type { ComponentProps, HTMLAttributes } from \"react\";\n\nexport type CheckpointProps = HTMLAttributes<HTMLDivElement>;\n\nexport const Checkpoint = ({ className, children, ...props }: CheckpointProps) => (\n <div\n className={cn(\"flex items-center gap-0.5 overflow-hidden text-muted-foreground\", className)}\n {...props}\n >\n {children}\n <Separator />\n </div>\n);\n\nexport type CheckpointIconProps = LucideProps;\n\nexport const CheckpointIcon = ({ className, children, ...props }: CheckpointIconProps) =>\n children ?? <BookmarkIcon className={cn(\"size-4 shrink-0\", className)} {...props} />;\n\nexport type CheckpointTriggerProps = ComponentProps<typeof Button> & {\n tooltip?: string;\n};\n\nexport const CheckpointTrigger = ({\n children,\n variant = \"ghost\",\n size = \"sm\",\n tooltip,\n ...props\n}: CheckpointTriggerProps) =>\n tooltip ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button size={size} type=\"button\" variant={variant} {...props}>\n {children}\n </Button>\n </TooltipTrigger>\n <TooltipContent align=\"start\" side=\"bottom\">\n {tooltip}\n </TooltipContent>\n </Tooltip>\n ) : (\n <Button size={size} type=\"button\" variant={variant} {...props}>\n {children}\n </Button>\n );\n"],"mappings":";;;AAEA,SAAS,cAAc;AACvB,SAAS,iBAAiB;AAC1B,SAAS,SAAS,gBAAgB,sBAAsB;AACxD,SAAS,UAAU;AAEnB,SAAS,oBAAoB;AAM3B,SAKE,KALF;AADK,IAAM,aAAa,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,MACzD;AAAA,EAAC;AAAA;AAAA,IACC,WAAW,GAAG,mEAAmE,SAAS;AAAA,IACzF,GAAG;AAAA,IAEH;AAAA;AAAA,MACD,oBAAC,aAAU;AAAA;AAAA;AACb;AAKK,IAAM,iBAAiB,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,MAC7D,YAAY,oBAAC,gBAAa,WAAW,GAAG,mBAAmB,SAAS,GAAI,GAAG,OAAO;AAM7E,IAAM,oBAAoB,CAAC;AAAA,EAChC;AAAA,EACA,UAAU;AAAA,EACV,OAAO;AAAA,EACP;AAAA,EACA,GAAG;AACL,MACE,UACE,qBAAC,WACC;AAAA,sBAAC,kBAAe,SAAO,MACrB,8BAAC,UAAO,MAAY,MAAK,UAAS,SAAmB,GAAG,OACrD,UACH,GACF;AAAA,EACA,oBAAC,kBAAe,OAAM,SAAQ,MAAK,UAChC,mBACH;AAAA,GACF,IAEA,oBAAC,UAAO,MAAY,MAAK,UAAS,SAAmB,GAAG,OACrD,UACH;","names":[]}
@@ -0,0 +1,192 @@
1
+ "use client";
2
+
3
+ // src/message-table-spec.ts
4
+ import { z } from "zod";
5
+ var cellFormatSchema = z.enum(["text", "number", "currency", "percent", "date", "badge"]);
6
+ var columnSpecSchema = z.object({
7
+ /** The row-object key this column reads. */
8
+ key: z.string(),
9
+ /** Header label. Falls back to the `key` when omitted. */
10
+ label: z.string().optional(),
11
+ /** How cells in this column are formatted + aligned. @default "text" */
12
+ format: cellFormatSchema.optional()
13
+ });
14
+ var tableSpecSchema = z.object({
15
+ /** Optional heading + accessible label for the table. */
16
+ title: z.string().optional(),
17
+ /** Ordered column definitions. */
18
+ columns: z.array(columnSpecSchema),
19
+ /** Row objects keyed by column `key`. */
20
+ rows: z.array(z.record(z.string(), z.unknown())),
21
+ /** Message shown when there are zero rows. @default "No rows to display" */
22
+ emptyText: z.string().optional()
23
+ });
24
+ function isPlainObject(value) {
25
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26
+ }
27
+ function strOrUndefined(value) {
28
+ return typeof value === "string" ? value : void 0;
29
+ }
30
+ function normalizeTableSpec(spec) {
31
+ if (!isPlainObject(spec)) {
32
+ return { ok: false, reason: "Table specification is missing or malformed." };
33
+ }
34
+ const columns = [];
35
+ const seen = /* @__PURE__ */ new Set();
36
+ if (Array.isArray(spec.columns)) {
37
+ for (const candidate of spec.columns) {
38
+ const parsed = columnSpecSchema.safeParse(candidate);
39
+ if (!parsed.success) continue;
40
+ if (seen.has(parsed.data.key)) continue;
41
+ seen.add(parsed.data.key);
42
+ columns.push(parsed.data);
43
+ }
44
+ }
45
+ const rows = Array.isArray(spec.rows) ? spec.rows.filter(isPlainObject) : [];
46
+ return {
47
+ ok: true,
48
+ spec: {
49
+ title: strOrUndefined(spec.title),
50
+ columns,
51
+ rows,
52
+ emptyText: strOrUndefined(spec.emptyText)
53
+ }
54
+ };
55
+ }
56
+ var EMPTY_CELL = "\u2014";
57
+ function isNumericFormat(format) {
58
+ return format === "number" || format === "currency" || format === "percent";
59
+ }
60
+ function isEmptyCell(value) {
61
+ return value === null || value === void 0 || value === "";
62
+ }
63
+ function toNumber(value) {
64
+ if (typeof value === "number") return value;
65
+ if (typeof value === "string" && value.trim() !== "") return Number(value);
66
+ return Number.NaN;
67
+ }
68
+ var numberFormatter = new Intl.NumberFormat(void 0, { maximumFractionDigits: 2 });
69
+ var currencyFormatter = new Intl.NumberFormat(void 0, {
70
+ style: "currency",
71
+ currency: "USD",
72
+ maximumFractionDigits: 0
73
+ });
74
+ var percentFormatter = new Intl.NumberFormat(void 0, {
75
+ style: "percent",
76
+ maximumFractionDigits: 1
77
+ });
78
+ function formatCellValue(value, format) {
79
+ switch (format) {
80
+ case "number": {
81
+ const n = toNumber(value);
82
+ return Number.isNaN(n) ? String(value) : numberFormatter.format(n);
83
+ }
84
+ case "currency": {
85
+ const n = toNumber(value);
86
+ return Number.isNaN(n) ? String(value) : currencyFormatter.format(n);
87
+ }
88
+ case "percent": {
89
+ const n = toNumber(value);
90
+ return Number.isNaN(n) ? String(value) : percentFormatter.format(n);
91
+ }
92
+ case "date": {
93
+ const d = value instanceof Date ? value : new Date(String(value));
94
+ return Number.isNaN(d.getTime()) ? String(value) : d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
95
+ }
96
+ default:
97
+ return String(value);
98
+ }
99
+ }
100
+ var SUCCESS_WORDS = /* @__PURE__ */ new Set([
101
+ "active",
102
+ "success",
103
+ "successful",
104
+ "complete",
105
+ "completed",
106
+ "done",
107
+ "passed",
108
+ "pass",
109
+ "approved",
110
+ "ok",
111
+ "online",
112
+ "enabled",
113
+ "healthy",
114
+ "live",
115
+ "paid",
116
+ "yes",
117
+ "true"
118
+ ]);
119
+ var WARNING_WORDS = /* @__PURE__ */ new Set([
120
+ "pending",
121
+ "warning",
122
+ "in progress",
123
+ "in-progress",
124
+ "review",
125
+ "in review",
126
+ "waiting",
127
+ "partial",
128
+ "degraded",
129
+ "low",
130
+ "hold",
131
+ "on hold"
132
+ ]);
133
+ var DESTRUCTIVE_WORDS = /* @__PURE__ */ new Set([
134
+ "failed",
135
+ "fail",
136
+ "error",
137
+ "rejected",
138
+ "inactive",
139
+ "offline",
140
+ "disabled",
141
+ "blocked",
142
+ "cancelled",
143
+ "canceled",
144
+ "overdue",
145
+ "no",
146
+ "false",
147
+ "critical",
148
+ "high",
149
+ "expired"
150
+ ]);
151
+ var INFO_WORDS = /* @__PURE__ */ new Set(["info", "new", "draft", "queued", "scheduled", "beta", "todo", "open"]);
152
+ function badgeToneForValue(value) {
153
+ const key = String(value).trim().toLowerCase();
154
+ if (SUCCESS_WORDS.has(key)) return "success";
155
+ if (WARNING_WORDS.has(key)) return "warning";
156
+ if (DESTRUCTIVE_WORDS.has(key)) return "destructive";
157
+ if (INFO_WORDS.has(key)) return "info";
158
+ return "secondary";
159
+ }
160
+ function compareCellValues(a, b, format) {
161
+ const aEmpty = isEmptyCell(a);
162
+ const bEmpty = isEmptyCell(b);
163
+ if (aEmpty && bEmpty) return 0;
164
+ if (aEmpty) return 1;
165
+ if (bEmpty) return -1;
166
+ if (isNumericFormat(format)) {
167
+ return toNumber(a) - toNumber(b);
168
+ }
169
+ if (format === "date") {
170
+ const da = new Date(String(a)).getTime();
171
+ const db = new Date(String(b)).getTime();
172
+ return (Number.isNaN(da) ? 0 : da) - (Number.isNaN(db) ? 0 : db);
173
+ }
174
+ const na = toNumber(a);
175
+ const nb = toNumber(b);
176
+ if (!Number.isNaN(na) && !Number.isNaN(nb)) return na - nb;
177
+ return String(a).localeCompare(String(b));
178
+ }
179
+
180
+ export {
181
+ cellFormatSchema,
182
+ columnSpecSchema,
183
+ tableSpecSchema,
184
+ normalizeTableSpec,
185
+ EMPTY_CELL,
186
+ isNumericFormat,
187
+ isEmptyCell,
188
+ formatCellValue,
189
+ badgeToneForValue,
190
+ compareCellValues
191
+ };
192
+ //# sourceMappingURL=chunk-DWJDJLPU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/message-table-spec.ts"],"sourcesContent":["/**\n * message-table-spec.ts — Serializable TableSpec for MessageTable.\n *\n * Pure data types + zod schemas (no React). The shape is what an LLM tool-call\n * emits when it wants to show tabular data inside a chat message. It is\n * column-oriented: `columns` declare the shape + per-column `format`, and each\n * `rows` entry is an object keyed by column `key`.\n *\n * The exported zod schemas are the source of truth downstream catalogs compile\n * prompts + validators from. Specs carry NO style-bearing props — the model\n * chooses the data and its semantic format, never the look.\n */\n\nimport { z } from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Columns\n// ---------------------------------------------------------------------------\n\n/**\n * How a cell's value is rendered + aligned.\n * - `text` (default) — as-is, start-aligned.\n * - `number` / `currency` / `percent` — `Intl`-formatted, end-aligned, tabular.\n * - `date` — localized date.\n * - `badge` — a tonal badge whose tone is inferred from the value's semantics.\n */\nexport const cellFormatSchema = z.enum([\"text\", \"number\", \"currency\", \"percent\", \"date\", \"badge\"]);\nexport type CellFormat = z.infer<typeof cellFormatSchema>;\n\n/** One column definition. */\nexport const columnSpecSchema = z.object({\n /** The row-object key this column reads. */\n key: z.string(),\n /** Header label. Falls back to the `key` when omitted. */\n label: z.string().optional(),\n /** How cells in this column are formatted + aligned. @default \"text\" */\n format: cellFormatSchema.optional(),\n});\nexport type ColumnSpec = z.infer<typeof columnSpecSchema>;\n\n// ---------------------------------------------------------------------------\n// TableSpec\n// ---------------------------------------------------------------------------\n\n/** A single row: an object keyed by column `key`. */\nexport type TableRowData = Record<string, unknown>;\n\n/**\n * The serializable table specification produced by an LLM tool-call.\n * MessageTable reads this and renders a lightweight, message-body table.\n */\nexport const tableSpecSchema = z.object({\n /** Optional heading + accessible label for the table. */\n title: z.string().optional(),\n /** Ordered column definitions. */\n columns: z.array(columnSpecSchema),\n /** Row objects keyed by column `key`. */\n rows: z.array(z.record(z.string(), z.unknown())),\n /** Message shown when there are zero rows. @default \"No rows to display\" */\n emptyText: z.string().optional(),\n});\nexport type TableSpec = z.infer<typeof tableSpecSchema>;\n\n// ---------------------------------------------------------------------------\n// Normalization (lenient — streaming-tolerant, never throws)\n// ---------------------------------------------------------------------------\n\n/** A validated, render-ready TableSpec. */\nexport interface NormalizedTableSpec {\n title?: string;\n columns: ColumnSpec[];\n rows: TableRowData[];\n emptyText?: string;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction strOrUndefined(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\n/**\n * Lenient parse for the render path. NEVER throws. Individually invalid columns\n * are dropped and non-object rows are filtered out, so a partial (streaming)\n * spec still renders progressively. Returns `{ ok: false }` only when the whole\n * spec is unusable (not an object).\n */\nexport function normalizeTableSpec(\n spec: unknown,\n): { ok: true; spec: NormalizedTableSpec } | { ok: false; reason: string } {\n if (!isPlainObject(spec)) {\n return { ok: false, reason: \"Table specification is missing or malformed.\" };\n }\n\n const columns: ColumnSpec[] = [];\n const seen = new Set<string>();\n if (Array.isArray(spec.columns)) {\n for (const candidate of spec.columns) {\n const parsed = columnSpecSchema.safeParse(candidate);\n if (!parsed.success) continue; // drop invalid / still-streaming column\n if (seen.has(parsed.data.key)) continue; // de-dupe by key\n seen.add(parsed.data.key);\n columns.push(parsed.data);\n }\n }\n\n const rows: TableRowData[] = Array.isArray(spec.rows) ? spec.rows.filter(isPlainObject) : [];\n\n return {\n ok: true,\n spec: {\n title: strOrUndefined(spec.title),\n columns,\n rows,\n emptyText: strOrUndefined(spec.emptyText),\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Formatting\n// ---------------------------------------------------------------------------\n\n/** The em-dash shown for a missing / empty cell. */\nexport const EMPTY_CELL = \"—\";\n\n/** Whether a format is numeric (drives end-alignment + `tabular-nums`). */\nexport function isNumericFormat(format: CellFormat | undefined): boolean {\n return format === \"number\" || format === \"currency\" || format === \"percent\";\n}\n\n/** Whether a value is considered empty (renders the em-dash). */\nexport function isEmptyCell(value: unknown): boolean {\n return value === null || value === undefined || value === \"\";\n}\n\nfunction toNumber(value: unknown): number {\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\" && value.trim() !== \"\") return Number(value);\n return Number.NaN;\n}\n\nconst numberFormatter = new Intl.NumberFormat(undefined, { maximumFractionDigits: 2 });\nconst currencyFormatter = new Intl.NumberFormat(undefined, {\n style: \"currency\",\n currency: \"USD\",\n maximumFractionDigits: 0,\n});\nconst percentFormatter = new Intl.NumberFormat(undefined, {\n style: \"percent\",\n maximumFractionDigits: 1,\n});\n\n/**\n * Format a present value to a display string per its column format.\n * Unknown formats fall through to `String(value)` (never throws). Empty values\n * are the caller's concern (render `EMPTY_CELL`). `percent` follows `Intl`\n * semantics — pass fractions (0.42 → \"42%\").\n */\nexport function formatCellValue(value: unknown, format: CellFormat | undefined): string {\n switch (format) {\n case \"number\": {\n const n = toNumber(value);\n return Number.isNaN(n) ? String(value) : numberFormatter.format(n);\n }\n case \"currency\": {\n const n = toNumber(value);\n return Number.isNaN(n) ? String(value) : currencyFormatter.format(n);\n }\n case \"percent\": {\n const n = toNumber(value);\n return Number.isNaN(n) ? String(value) : percentFormatter.format(n);\n }\n case \"date\": {\n const d = value instanceof Date ? value : new Date(String(value));\n return Number.isNaN(d.getTime())\n ? String(value)\n : d.toLocaleDateString(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" });\n }\n default:\n return String(value);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Badge tone inference (semantic, not style — the spec never picks a tone)\n// ---------------------------------------------------------------------------\n\nexport type BadgeTone = \"secondary\" | \"success\" | \"warning\" | \"destructive\" | \"info\";\n\nconst SUCCESS_WORDS = new Set([\n \"active\",\n \"success\",\n \"successful\",\n \"complete\",\n \"completed\",\n \"done\",\n \"passed\",\n \"pass\",\n \"approved\",\n \"ok\",\n \"online\",\n \"enabled\",\n \"healthy\",\n \"live\",\n \"paid\",\n \"yes\",\n \"true\",\n]);\nconst WARNING_WORDS = new Set([\n \"pending\",\n \"warning\",\n \"in progress\",\n \"in-progress\",\n \"review\",\n \"in review\",\n \"waiting\",\n \"partial\",\n \"degraded\",\n \"low\",\n \"hold\",\n \"on hold\",\n]);\nconst DESTRUCTIVE_WORDS = new Set([\n \"failed\",\n \"fail\",\n \"error\",\n \"rejected\",\n \"inactive\",\n \"offline\",\n \"disabled\",\n \"blocked\",\n \"cancelled\",\n \"canceled\",\n \"overdue\",\n \"no\",\n \"false\",\n \"critical\",\n \"high\",\n \"expired\",\n]);\nconst INFO_WORDS = new Set([\"info\", \"new\", \"draft\", \"queued\", \"scheduled\", \"beta\", \"todo\", \"open\"]);\n\n/** Infer a badge tone from a value's semantics (status vocabulary). */\nexport function badgeToneForValue(value: unknown): BadgeTone {\n const key = String(value).trim().toLowerCase();\n if (SUCCESS_WORDS.has(key)) return \"success\";\n if (WARNING_WORDS.has(key)) return \"warning\";\n if (DESTRUCTIVE_WORDS.has(key)) return \"destructive\";\n if (INFO_WORDS.has(key)) return \"info\";\n return \"secondary\";\n}\n\n// ---------------------------------------------------------------------------\n// Sorting\n// ---------------------------------------------------------------------------\n\n/** Compare two cell values for sorting, honoring numeric/date formats. */\nexport function compareCellValues(a: unknown, b: unknown, format: CellFormat | undefined): number {\n const aEmpty = isEmptyCell(a);\n const bEmpty = isEmptyCell(b);\n if (aEmpty && bEmpty) return 0;\n if (aEmpty) return 1; // empties sort last\n if (bEmpty) return -1;\n\n if (isNumericFormat(format)) {\n return toNumber(a) - toNumber(b);\n }\n if (format === \"date\") {\n const da = new Date(String(a)).getTime();\n const db = new Date(String(b)).getTime();\n return (Number.isNaN(da) ? 0 : da) - (Number.isNaN(db) ? 0 : db);\n }\n // Mixed/auto: numeric when both parse as numbers, else locale string compare.\n const na = toNumber(a);\n const nb = toNumber(b);\n if (!Number.isNaN(na) && !Number.isNaN(nb)) return na - nb;\n return String(a).localeCompare(String(b));\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,45 @@
1
+ "use client";
2
+
3
+ // src/_streamdown-safety.ts
4
+ var SANITIZER_OVERRIDE_KEYS = ["rehypePlugins"];
5
+ function stripSanitizerOverrides(props) {
6
+ const record = props;
7
+ for (const key of SANITIZER_OVERRIDE_KEYS) {
8
+ if (key in record) {
9
+ if (process.env.NODE_ENV !== "production") {
10
+ console.warn(
11
+ `[@elabs-ai/components-ai] \`${key}\` is not a supported prop on this component: it would replace Streamdown's default sanitiser chain (rehype-raw \u2192 rehype-sanitize \u2192 rehype-harden) and let untrusted markdown execute script in the host page. The value was ignored. Use \`allowedTags\` / \`literalTagContent\` to widen sanitisation instead \u2014 see issue #36.`
12
+ );
13
+ }
14
+ delete record[key];
15
+ }
16
+ }
17
+ }
18
+ var TRUSTED_PLUGIN_SLOT_ADVICE = "This is a supported, TRUSTED-CODE seam \u2014 the plugin still runs and nothing was dropped \u2014 so treat it as code you ship: it can put arbitrary markup in the page. If you only needed KaTeX options, prefer `createMathPlugin({ singleDollarTextMath, errorColor })` and leave KaTeX's `trust` option off for model-authored content. See docs/CSP-AND-NETWORK.md and issue #76.";
19
+ var isPluginObject = (value) => typeof value === "object" && value !== null;
20
+ function warnOnTrustedPluginSlots(overrides, internal) {
21
+ if (process.env.NODE_ENV === "production") return;
22
+ if (!overrides) return;
23
+ const consumer = overrides;
24
+ const defaults = internal;
25
+ if (isPluginObject(consumer.math)) {
26
+ const theirs = consumer.math.rehypePlugin;
27
+ const ours = isPluginObject(defaults.math) ? defaults.math.rehypePlugin : void 0;
28
+ if (theirs !== ours) {
29
+ console.warn(
30
+ `[@elabs-ai/components-ai] \`plugins.math.rehypePlugin\` is appended to the END of Streamdown's rehype pipeline, so it runs AFTER the sanitiser chain (rehype-raw \u2192 rehype-sanitize \u2192 rehype-harden) and whatever it emits is never re-sanitised. ${TRUSTED_PLUGIN_SLOT_ADVICE}`
31
+ );
32
+ }
33
+ }
34
+ if (isPluginObject(consumer.mermaid) && consumer.mermaid !== defaults.mermaid) {
35
+ console.warn(
36
+ `[@elabs-ai/components-ai] \`plugins.mermaid\` never enters the rehype pipeline at all: its rendered SVG is injected as raw HTML through React's dangerous inner-HTML prop, i.e. after and outside the sanitiser chain (rehype-raw \u2192 rehype-sanitize \u2192 rehype-harden). A replacement plugin must sanitise its own output \u2014 brand-ui's default pins mermaid's strict security level. ${TRUSTED_PLUGIN_SLOT_ADVICE}`
37
+ );
38
+ }
39
+ }
40
+
41
+ export {
42
+ stripSanitizerOverrides,
43
+ warnOnTrustedPluginSlots
44
+ };
45
+ //# sourceMappingURL=chunk-DZW6LM22.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/_streamdown-safety.ts"],"sourcesContent":["/**\n * The runtime half of the #36 fix (the type-level `Omit` is the other half — see\n * `MarkdownViewProps`/`MessageResponseProps`).\n *\n * Streamdown installs its sanitiser chain (`rehype-raw` → `rehype-sanitize` →\n * `rehype-harden`) as the DEFAULT VALUE of its `rehypePlugins` prop — a plain\n * JS default parameter. Supplying the prop REPLACES the whole chain; there is\n * no merge (verified against `streamdown@2.5.0`'s `dist/chunk-BO2N2NFS.js`:\n * `xt = { raw, sanitize, harden }; gn = Object.values(xt)` is the default, and\n * the component signature reads `rehypePlugins: a = gn`).\n *\n * `MarkdownView`/`MessageResponse` render UNTRUSTED, model-authored markdown,\n * so that prop may never reach `<Streamdown>` — not even through a plain\n * JavaScript consumer, an `as any`/`as never` cast, or a wider\n * `{...spreadProps}` object a type-level `Omit` cannot see at runtime. `Omit`\n * closes the TypeScript surface; this function closes the runtime one. Both\n * are required — see issue #36.\n *\n * `remarkPlugins` is deliberately NOT stripped (PR #74 review, round 1). It is\n * the same *shape* of prop — a consumer array replaces Streamdown's own remark\n * defaults (`gfm`, `codeMeta`) rather than merging with them — but it is NOT a\n * sanitiser override: the remark stage runs strictly UPSTREAM of the rehype\n * chain, and Streamdown derives its rehype list without reading `remarkPlugins`\n * at all. Anything a remark plugin injects — a raw `html` mdast node, a\n * `data.hName`/`hChildren` hast element, an `onerror` via `hProperties`, a\n * `javascript:` link URL, a smuggled `raw` hast child — still passes through\n * `rehype-raw` → `rehype-sanitize` → `rehype-harden` before it can reach the\n * DOM. Measured with this strip removed: all five channels executed and none\n * produced a `<script>`, an `[onerror]` attribute or a `javascript:` href,\n * while the identical payload injected AFTER the sanitiser did. Stripping it\n * therefore removed real capability (remark-directive, footnotes, custom\n * syntax) and closed nothing.\n *\n * If a consumer needs to widen what survives SANITISATION, `allowedTags` /\n * `literalTagContent` are the supported seam: they MERGE into the sanitize\n * schema instead of replacing the pipeline outright.\n *\n * THIS LIST HAS A PARITY COUNTERPART, AND EDITING ONE SIDE FAILS CI (#75).\n * `scripts/check/rules/sanitizer-passthrough.mjs` declares the same key set as\n * `SAFE_RENDERERS[streamdown].dangerousProps` and reads THIS array literal back\n * out of this file, asserting set-equality in BOTH directions — so removing a\n * key here (the runtime stops stripping it) and removing a key there (the gate\n * stops looking for it) are each a red build, and so is renaming the constant\n * or rewriting it into a shape the gate cannot parse. Change the key set in\n * both places, in the same commit, or don't change it.\n */\nconst SANITIZER_OVERRIDE_KEYS = [\"rehypePlugins\"] as const;\n\n/**\n * Deletes `rehypePlugins` off `props` in place (if present) and warns in dev.\n * Call this BEFORE spreading `props` onto `<Streamdown>`.\n *\n * Takes a plain object rather than a typed `MarkdownViewProps`/\n * `MessageResponseProps` on purpose: the whole point is to catch a value that\n * reached this call with a wider runtime shape than its type says (a `.tsx`\n * consumer with no type checking at all, a force-cast, a spread of a bigger\n * object) — a parameter typed to the post-`Omit` props would only accept\n * values TypeScript already believes are safe.\n */\nexport function stripSanitizerOverrides(props: object): void {\n const record = props as Record<string, unknown>;\n for (const key of SANITIZER_OVERRIDE_KEYS) {\n if (key in record) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[@elabs-ai/components-ai] \\`${key}\\` is not a supported prop on this component: ` +\n \"it would replace Streamdown's default sanitiser chain (rehype-raw → \" +\n \"rehype-sanitize → rehype-harden) and let untrusted markdown execute \" +\n \"script in the host page. The value was ignored. Use `allowedTags` / \" +\n \"`literalTagContent` to widen sanitisation instead — see issue #36.\",\n );\n }\n delete record[key];\n }\n }\n}\n\n/**\n * The CONVERSE of `SANITIZER_OVERRIDE_KEYS`: the plugin slots that deliberately\n * stay reachable even though they land in the DOM *after* — or entirely outside\n * — Streamdown's sanitiser chain (#76).\n *\n * - **`math.rehypePlugin` is APPENDED to the END of the rehype pipeline**, i.e.\n * after `rehype-raw` → `rehype-sanitize` → `rehype-harden` (verified against\n * `streamdown@2.5.0`'s `dist/chunk-BO2N2NFS.js`). Its output is never\n * re-sanitised.\n * - **`mermaid` never enters the rehype/remark pipeline at all.** Its\n * `getMermaid().render()` result is written via `dangerouslySetInnerHTML`\n * (streamdown's only such sink). brand-ui's own default pins mermaid's\n * `securityLevel: \"strict\"` (`_lazy-mermaid.ts`).\n *\n * `cjk` (remark-stage, re-sanitised downstream), `code` (feeds `shikiTheme`\n * only) and `renderers` (ordinary React components) are NOT trust-bearing and\n * are deliberately absent — a warning that fired on them would be noise\n * consumers learn to ignore.\n *\n * **This is not a live vulnerability and must not be described as one.**\n * Supplying an executable `Pluggable` takes code in the consuming app's own\n * bundle, and an app author who can do that can already run code. The real,\n * non-hypothetical hazard is MISCONFIGURATION — most sharply KaTeX's `trust`\n * option (needed for anything beyond `singleDollarTextMath`/`errorColor`),\n * which silently disables KaTeX's own sanitisation for model-authored content\n * the consumer never intended to trust. Hence: WARN, never strip. Stripping\n * would break the legitimate trusted use and is the breaking change #76\n * explicitly rejects — `markdown-view.test.tsx`/`message.test.tsx` pin the slot\n * OPEN so a future \"hardening\" fails loudly.\n */\nconst TRUSTED_PLUGIN_SLOT_ADVICE =\n \"This is a supported, TRUSTED-CODE seam — the plugin still runs and nothing was \" +\n \"dropped — so treat it as code you ship: it can put arbitrary markup in the page. \" +\n \"If you only needed KaTeX options, prefer `createMathPlugin({ singleDollarTextMath, \" +\n \"errorColor })` and leave KaTeX's `trust` option off for model-authored content. \" +\n \"See docs/CSP-AND-NETWORK.md and issue #76.\";\n\nconst isPluginObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\n/**\n * Dev-only `console.warn` when a consumer's `plugins` override replaces one of\n * the two slots that are NOT upstream of the sanitiser. Call it where the\n * consumer's overrides are merged over the internal defaults, passing both.\n *\n * **Reference-equality comparator, deliberately — not truthiness, not a deep\n * compare.** `useStreamdownPlugins()` returns a FRESH `code` object on every\n * theme change but a STABLE `math`/`mermaid`, so a truthiness check would fire\n * on every theme flip and a deep-equality check would stay silent for a consumer\n * who rebuilds an equivalent-looking object each render. For `math` the\n * comparison narrows further to the `rehypePlugin` member itself, so changing\n * only `remarkPlugin`/`getStyles` (upstream of, or outside, the DOM sink) stays\n * silent.\n *\n * Warns; never mutates. `stripSanitizerOverrides` is the other half of the\n * boundary — the props that must never be reachable at all.\n */\nexport function warnOnTrustedPluginSlots(overrides: object | undefined, internal: object): void {\n if (process.env.NODE_ENV === \"production\") return;\n if (!overrides) return;\n const consumer = overrides as Record<string, unknown>;\n const defaults = internal as Record<string, unknown>;\n\n if (isPluginObject(consumer.math)) {\n const theirs = consumer.math.rehypePlugin;\n const ours = isPluginObject(defaults.math) ? defaults.math.rehypePlugin : undefined;\n if (theirs !== ours) {\n console.warn(\n \"[@elabs-ai/components-ai] `plugins.math.rehypePlugin` is appended to the END of \" +\n \"Streamdown's rehype pipeline, so it runs AFTER the sanitiser chain \" +\n \"(rehype-raw → rehype-sanitize → rehype-harden) and whatever it emits is never \" +\n `re-sanitised. ${TRUSTED_PLUGIN_SLOT_ADVICE}`,\n );\n }\n }\n\n if (isPluginObject(consumer.mermaid) && consumer.mermaid !== defaults.mermaid) {\n // The message describes React's `dangerouslySetInnerHTML` in prose rather than\n // naming the identifier: the `trusted-types-sinks` check preserves string literals on\n // purpose (a sink hidden in a string is still a sink), so spelling the prop out\n // inside this warning makes the gate read THIS file as a new HTML-assigning\n // module. Comments like this one are stripped by that gate, so the name is safe\n // here and in the TSDoc above — just not inside a runtime string.\n console.warn(\n \"[@elabs-ai/components-ai] `plugins.mermaid` never enters the rehype pipeline at \" +\n \"all: its rendered SVG is injected as raw HTML through React's dangerous \" +\n \"inner-HTML prop, i.e. after and outside the sanitiser chain \" +\n \"(rehype-raw → rehype-sanitize → rehype-harden). A \" +\n \"replacement plugin must sanitise its own output — brand-ui's default pins \" +\n `mermaid's strict security level. ${TRUSTED_PLUGIN_SLOT_ADVICE}`,\n );\n }\n}\n"],"mappings":";;;AA8CA,IAAM,0BAA0B,CAAC,eAAe;AAazC,SAAS,wBAAwB,OAAqB;AAC3D,QAAM,SAAS;AACf,aAAW,OAAO,yBAAyB;AACzC,QAAI,OAAO,QAAQ;AACjB,UAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,gBAAQ;AAAA,UACN,+BAA+B,GAAG;AAAA,QAKpC;AAAA,MACF;AACA,aAAO,OAAO,GAAG;AAAA,IACnB;AAAA,EACF;AACF;AAgCA,IAAM,6BACJ;AAMF,IAAM,iBAAiB,CAAC,UACtB,OAAO,UAAU,YAAY,UAAU;AAmBlC,SAAS,yBAAyB,WAA+B,UAAwB;AAC9F,MAAI,QAAQ,IAAI,aAAa,aAAc;AAC3C,MAAI,CAAC,UAAW;AAChB,QAAM,WAAW;AACjB,QAAM,WAAW;AAEjB,MAAI,eAAe,SAAS,IAAI,GAAG;AACjC,UAAM,SAAS,SAAS,KAAK;AAC7B,UAAM,OAAO,eAAe,SAAS,IAAI,IAAI,SAAS,KAAK,eAAe;AAC1E,QAAI,WAAW,MAAM;AACnB,cAAQ;AAAA,QACN,8PAGmB,0BAA0B;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAEA,MAAI,eAAe,SAAS,OAAO,KAAK,SAAS,YAAY,SAAS,SAAS;AAO7E,YAAQ;AAAA,MACN,qYAKsC,0BAA0B;AAAA,IAClE;AAAA,EACF;AACF;","names":[]}