@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,197 @@
1
+ "use client";
2
+
3
+ // src/commit.tsx
4
+ import { Avatar, AvatarFallback } from "@elabs-ai/components-ui";
5
+ import { Button } from "@elabs-ai/components-ui";
6
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@elabs-ai/components-ui";
7
+ import { useCopyToClipboard, useLocale } from "@elabs-ai/components-ui";
8
+ import { cn } from "@elabs-ai/components-ui/lib/cn";
9
+ import { CheckIcon, CopyIcon, FileIcon, GitCommitIcon, MinusIcon, PlusIcon } from "lucide-react";
10
+ import { useCallback, useEffect, useState } from "react";
11
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
+ var Commit = ({ className, children, ...props }) => /* @__PURE__ */ jsx(Collapsible, { className: cn("rounded-lg border bg-background", className), ...props, children });
13
+ var CommitHeader = ({ className, children, ...props }) => /* @__PURE__ */ jsx(CollapsibleTrigger, { asChild: true, ...props, children: /* @__PURE__ */ jsx(
14
+ "div",
15
+ {
16
+ className: cn(
17
+ "group flex cursor-pointer items-center justify-between gap-4 p-3 text-start transition-colors hover:opacity-80",
18
+ className
19
+ ),
20
+ children
21
+ }
22
+ ) });
23
+ var CommitHash = ({ className, children, ...props }) => /* @__PURE__ */ jsxs("span", { className: cn("font-mono text-meta", className), ...props, children: [
24
+ /* @__PURE__ */ jsx(GitCommitIcon, { className: "me-1 inline-block size-3" }),
25
+ children
26
+ ] });
27
+ var CommitMessage = ({ className, children, ...props }) => /* @__PURE__ */ jsx("span", { className: cn("font-medium text-body", className), ...props, children });
28
+ var CommitMetadata = ({ className, children, ...props }) => /* @__PURE__ */ jsx(
29
+ "div",
30
+ {
31
+ className: cn("flex items-center gap-2 text-muted-foreground text-meta", className),
32
+ ...props,
33
+ children
34
+ }
35
+ );
36
+ var CommitSeparator = ({ className, children, ...props }) => /* @__PURE__ */ jsx("span", { className, ...props, children: children ?? "\u2022" });
37
+ var CommitInfo = ({ className, children, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex flex-1 flex-col", className), ...props, children });
38
+ var CommitAuthor = ({ className, children, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex items-center", className), ...props, children });
39
+ var CommitAuthorAvatar = ({ initials, className, ...props }) => /* @__PURE__ */ jsx(Avatar, { className: cn("size-8", className), ...props, children: /* @__PURE__ */ jsx(AvatarFallback, { className: "text-meta", children: initials }) });
40
+ var formatRelativeDate = (date, locale) => {
41
+ const days = Math.round((date.getTime() - Date.now()) / (1e3 * 60 * 60 * 24));
42
+ return new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(days, "day");
43
+ };
44
+ var CommitTimestamp = ({ date, className, children, ...props }) => {
45
+ const { locale } = useLocale();
46
+ const [formatted, setFormatted] = useState("");
47
+ const updateFormatted = useCallback(() => {
48
+ setFormatted(formatRelativeDate(date, locale));
49
+ }, [date, locale]);
50
+ useEffect(() => {
51
+ updateFormatted();
52
+ }, [updateFormatted]);
53
+ return /* @__PURE__ */ jsx("time", { className: cn("text-meta", className), dateTime: date.toISOString(), ...props, children: children ?? formatted });
54
+ };
55
+ var handleActionsClick = (e) => e.stopPropagation();
56
+ var handleActionsKeyDown = (e) => e.stopPropagation();
57
+ var CommitActions = ({ className, children, ...props }) => /* @__PURE__ */ jsx(
58
+ "div",
59
+ {
60
+ className: cn("flex items-center gap-1", className),
61
+ onClick: handleActionsClick,
62
+ onKeyDown: handleActionsKeyDown,
63
+ role: "group",
64
+ ...props,
65
+ children
66
+ }
67
+ );
68
+ var CommitCopyButton = ({
69
+ hash,
70
+ onCopy,
71
+ onError,
72
+ timeout,
73
+ children,
74
+ className,
75
+ "aria-label": ariaLabel,
76
+ ...props
77
+ }) => {
78
+ const { t } = useLocale();
79
+ const { copied: isCopied, copy } = useCopyToClipboard({ resetAfterMs: timeout ?? 2e3 });
80
+ const copyToClipboard = useCallback(async () => {
81
+ const ok = await copy(hash);
82
+ if (ok) {
83
+ onCopy?.();
84
+ } else {
85
+ onError?.(new Error("Clipboard API not available"));
86
+ }
87
+ }, [copy, hash, onCopy, onError]);
88
+ const Icon = isCopied ? CheckIcon : CopyIcon;
89
+ return /* @__PURE__ */ jsx(
90
+ Button,
91
+ {
92
+ "aria-label": ariaLabel ?? t("copy"),
93
+ className: cn("size-7 shrink-0", className),
94
+ onClick: copyToClipboard,
95
+ size: "icon",
96
+ variant: "ghost",
97
+ ...props,
98
+ children: children ?? /* @__PURE__ */ jsx(Icon, { size: 14 })
99
+ }
100
+ );
101
+ };
102
+ var CommitContent = ({ className, children, ...props }) => /* @__PURE__ */ jsx(CollapsibleContent, { className: cn("border-t p-3", className), ...props, children });
103
+ var CommitFiles = ({ className, children, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("space-y-1", className), ...props, children });
104
+ var CommitFile = ({ className, children, ...props }) => /* @__PURE__ */ jsx(
105
+ "div",
106
+ {
107
+ className: cn(
108
+ "flex items-center justify-between gap-2 rounded px-2 py-1 text-body hover:bg-muted/50",
109
+ className
110
+ ),
111
+ ...props,
112
+ children
113
+ }
114
+ );
115
+ var CommitFileInfo = ({ className, children, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex min-w-0 items-center gap-2", className), ...props, children });
116
+ var fileStatusStyles = {
117
+ added: "text-success-text",
118
+ deleted: "text-destructive-text",
119
+ modified: "text-warning-text",
120
+ renamed: "text-info-text"
121
+ };
122
+ var fileStatusLabels = {
123
+ added: "A",
124
+ deleted: "D",
125
+ modified: "M",
126
+ renamed: "R"
127
+ };
128
+ var CommitFileStatus = ({
129
+ status,
130
+ className,
131
+ children,
132
+ ...props
133
+ }) => /* @__PURE__ */ jsx(
134
+ "span",
135
+ {
136
+ className: cn("font-medium font-mono text-meta", fileStatusStyles[status], className),
137
+ ...props,
138
+ children: children ?? fileStatusLabels[status]
139
+ }
140
+ );
141
+ var CommitFileIcon = ({ className, ...props }) => /* @__PURE__ */ jsx(FileIcon, { className: cn("size-3.5 shrink-0 text-muted-foreground", className), ...props });
142
+ var CommitFilePath = ({ className, children, ...props }) => /* @__PURE__ */ jsx("span", { className: cn("truncate font-mono text-meta", className), ...props, children });
143
+ var CommitFileChanges = ({ className, children, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex shrink-0 items-center gap-1 font-mono text-meta", className), ...props, children });
144
+ var CommitFileAdditions = ({
145
+ count,
146
+ className,
147
+ children,
148
+ ...props
149
+ }) => {
150
+ if (count <= 0) {
151
+ return null;
152
+ }
153
+ return /* @__PURE__ */ jsx("span", { className: cn("text-success-text", className), ...props, children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
154
+ /* @__PURE__ */ jsx(PlusIcon, { className: "inline-block size-3" }),
155
+ count
156
+ ] }) });
157
+ };
158
+ var CommitFileDeletions = ({
159
+ count,
160
+ className,
161
+ children,
162
+ ...props
163
+ }) => {
164
+ if (count <= 0) {
165
+ return null;
166
+ }
167
+ return /* @__PURE__ */ jsx("span", { className: cn("text-destructive-text", className), ...props, children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
168
+ /* @__PURE__ */ jsx(MinusIcon, { className: "inline-block size-3" }),
169
+ count
170
+ ] }) });
171
+ };
172
+
173
+ export {
174
+ Commit,
175
+ CommitHeader,
176
+ CommitHash,
177
+ CommitMessage,
178
+ CommitMetadata,
179
+ CommitSeparator,
180
+ CommitInfo,
181
+ CommitAuthor,
182
+ CommitAuthorAvatar,
183
+ CommitTimestamp,
184
+ CommitActions,
185
+ CommitCopyButton,
186
+ CommitContent,
187
+ CommitFiles,
188
+ CommitFile,
189
+ CommitFileInfo,
190
+ CommitFileStatus,
191
+ CommitFileIcon,
192
+ CommitFilePath,
193
+ CommitFileChanges,
194
+ CommitFileAdditions,
195
+ CommitFileDeletions
196
+ };
197
+ //# sourceMappingURL=chunk-UCKFJ3QF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commit.tsx"],"sourcesContent":["\"use client\";\n\nimport { Avatar, AvatarFallback } from \"@elabs-ai/components-ui\";\nimport { Button } from \"@elabs-ai/components-ui\";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"@elabs-ai/components-ui\";\nimport { useCopyToClipboard, useLocale } from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport { CheckIcon, CopyIcon, FileIcon, GitCommitIcon, MinusIcon, PlusIcon } from \"lucide-react\";\nimport type { ComponentProps, HTMLAttributes } from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nexport type CommitProps = ComponentProps<typeof Collapsible>;\n\nexport const Commit = ({ className, children, ...props }: CommitProps) => (\n <Collapsible className={cn(\"rounded-lg border bg-background\", className)} {...props}>\n {children}\n </Collapsible>\n);\n\nexport type CommitHeaderProps = ComponentProps<typeof CollapsibleTrigger>;\n\nexport const CommitHeader = ({ className, children, ...props }: CommitHeaderProps) => (\n <CollapsibleTrigger asChild {...props}>\n <div\n className={cn(\n \"group flex cursor-pointer items-center justify-between gap-4 p-3 text-start transition-colors hover:opacity-80\",\n className,\n )}\n >\n {children}\n </div>\n </CollapsibleTrigger>\n);\n\nexport type CommitHashProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const CommitHash = ({ className, children, ...props }: CommitHashProps) => (\n <span className={cn(\"font-mono text-meta\", className)} {...props}>\n <GitCommitIcon className=\"me-1 inline-block size-3\" />\n {children}\n </span>\n);\n\nexport type CommitMessageProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const CommitMessage = ({ className, children, ...props }: CommitMessageProps) => (\n <span className={cn(\"font-medium text-body\", className)} {...props}>\n {children}\n </span>\n);\n\nexport type CommitMetadataProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitMetadata = ({ className, children, ...props }: CommitMetadataProps) => (\n <div\n className={cn(\"flex items-center gap-2 text-muted-foreground text-meta\", className)}\n {...props}\n >\n {children}\n </div>\n);\n\nexport type CommitSeparatorProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const CommitSeparator = ({ className, children, ...props }: CommitSeparatorProps) => (\n <span className={className} {...props}>\n {children ?? \"•\"}\n </span>\n);\n\nexport type CommitInfoProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitInfo = ({ className, children, ...props }: CommitInfoProps) => (\n <div className={cn(\"flex flex-1 flex-col\", className)} {...props}>\n {children}\n </div>\n);\n\nexport type CommitAuthorProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitAuthor = ({ className, children, ...props }: CommitAuthorProps) => (\n <div className={cn(\"flex items-center\", className)} {...props}>\n {children}\n </div>\n);\n\nexport type CommitAuthorAvatarProps = ComponentProps<typeof Avatar> & {\n initials: string;\n};\n\nexport const CommitAuthorAvatar = ({ initials, className, ...props }: CommitAuthorAvatarProps) => (\n <Avatar className={cn(\"size-8\", className)} {...props}>\n <AvatarFallback className=\"text-meta\">{initials}</AvatarFallback>\n </Avatar>\n);\n\nexport type CommitTimestampProps = HTMLAttributes<HTMLTimeElement> & {\n date: Date;\n};\n\nconst formatRelativeDate = (date: Date, locale: string) => {\n const days = Math.round((date.getTime() - Date.now()) / (1000 * 60 * 60 * 24));\n return new Intl.RelativeTimeFormat(locale, { numeric: \"auto\" }).format(days, \"day\");\n};\n\nexport const CommitTimestamp = ({ date, className, children, ...props }: CommitTimestampProps) => {\n const { locale } = useLocale();\n const [formatted, setFormatted] = useState(\"\");\n\n const updateFormatted = useCallback(() => {\n setFormatted(formatRelativeDate(date, locale));\n }, [date, locale]);\n\n useEffect(() => {\n updateFormatted();\n }, [updateFormatted]);\n\n return (\n <time className={cn(\"text-meta\", className)} dateTime={date.toISOString()} {...props}>\n {children ?? formatted}\n </time>\n );\n};\n\nexport type CommitActionsProps = HTMLAttributes<HTMLDivElement>;\n\nconst handleActionsClick = (e: React.MouseEvent) => e.stopPropagation();\nconst handleActionsKeyDown = (e: React.KeyboardEvent) => e.stopPropagation();\n\nexport const CommitActions = ({ className, children, ...props }: CommitActionsProps) => (\n <div\n className={cn(\"flex items-center gap-1\", className)}\n onClick={handleActionsClick}\n onKeyDown={handleActionsKeyDown}\n role=\"group\"\n {...props}\n >\n {children}\n </div>\n);\n\nexport type CommitCopyButtonProps = ComponentProps<typeof Button> & {\n hash: string;\n onCopy?: () => void;\n onError?: (error: Error) => void;\n timeout?: number;\n};\n\nexport const CommitCopyButton = ({\n hash,\n onCopy,\n onError,\n timeout,\n children,\n className,\n \"aria-label\": ariaLabel,\n ...props\n}: CommitCopyButtonProps) => {\n const { t } = useLocale();\n // Shared implementation (`@elabs-ai/components-ui`) instead of a private\n // copy of the same copy-to-clipboard state machine (issue-workflow.md\n // dedupe finding) — see `CodeBlockCopyButton` for the reference usage.\n const { copied: isCopied, copy } = useCopyToClipboard({ resetAfterMs: timeout ?? 2000 });\n\n const copyToClipboard = useCallback(async () => {\n const ok = await copy(hash);\n if (ok) {\n onCopy?.();\n } else {\n onError?.(new Error(\"Clipboard API not available\"));\n }\n }, [copy, hash, onCopy, onError]);\n\n const Icon = isCopied ? CheckIcon : CopyIcon;\n\n return (\n <Button\n aria-label={ariaLabel ?? t(\"copy\")}\n className={cn(\"size-7 shrink-0\", className)}\n onClick={copyToClipboard}\n size=\"icon\"\n variant=\"ghost\"\n {...props}\n >\n {children ?? <Icon size={14} />}\n </Button>\n );\n};\n\nexport type CommitContentProps = ComponentProps<typeof CollapsibleContent>;\n\nexport const CommitContent = ({ className, children, ...props }: CommitContentProps) => (\n <CollapsibleContent className={cn(\"border-t p-3\", className)} {...props}>\n {children}\n </CollapsibleContent>\n);\n\nexport type CommitFilesProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitFiles = ({ className, children, ...props }: CommitFilesProps) => (\n <div className={cn(\"space-y-1\", className)} {...props}>\n {children}\n </div>\n);\n\nexport type CommitFileProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitFile = ({ className, children, ...props }: CommitFileProps) => (\n <div\n className={cn(\n \"flex items-center justify-between gap-2 rounded px-2 py-1 text-body hover:bg-muted/50\",\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n\nexport type CommitFileInfoProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitFileInfo = ({ className, children, ...props }: CommitFileInfoProps) => (\n <div className={cn(\"flex min-w-0 items-center gap-2\", className)} {...props}>\n {children}\n </div>\n);\n\nconst fileStatusStyles = {\n added: \"text-success-text\",\n deleted: \"text-destructive-text\",\n modified: \"text-warning-text\",\n renamed: \"text-info-text\",\n};\n\nconst fileStatusLabels = {\n added: \"A\",\n deleted: \"D\",\n modified: \"M\",\n renamed: \"R\",\n};\n\nexport type CommitFileStatusProps = HTMLAttributes<HTMLSpanElement> & {\n status: \"added\" | \"modified\" | \"deleted\" | \"renamed\";\n};\n\nexport const CommitFileStatus = ({\n status,\n className,\n children,\n ...props\n}: CommitFileStatusProps) => (\n <span\n className={cn(\"font-medium font-mono text-meta\", fileStatusStyles[status], className)}\n {...props}\n >\n {children ?? fileStatusLabels[status]}\n </span>\n);\n\nexport type CommitFileIconProps = ComponentProps<typeof FileIcon>;\n\nexport const CommitFileIcon = ({ className, ...props }: CommitFileIconProps) => (\n <FileIcon className={cn(\"size-3.5 shrink-0 text-muted-foreground\", className)} {...props} />\n);\n\nexport type CommitFilePathProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const CommitFilePath = ({ className, children, ...props }: CommitFilePathProps) => (\n <span className={cn(\"truncate font-mono text-meta\", className)} {...props}>\n {children}\n </span>\n);\n\nexport type CommitFileChangesProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitFileChanges = ({ className, children, ...props }: CommitFileChangesProps) => (\n <div className={cn(\"flex shrink-0 items-center gap-1 font-mono text-meta\", className)} {...props}>\n {children}\n </div>\n);\n\nexport type CommitFileAdditionsProps = HTMLAttributes<HTMLSpanElement> & {\n count: number;\n};\n\nexport const CommitFileAdditions = ({\n count,\n className,\n children,\n ...props\n}: CommitFileAdditionsProps) => {\n if (count <= 0) {\n return null;\n }\n\n return (\n <span className={cn(\"text-success-text\", className)} {...props}>\n {children ?? (\n <>\n <PlusIcon className=\"inline-block size-3\" />\n {count}\n </>\n )}\n </span>\n );\n};\n\nexport type CommitFileDeletionsProps = HTMLAttributes<HTMLSpanElement> & {\n count: number;\n};\n\nexport const CommitFileDeletions = ({\n count,\n className,\n children,\n ...props\n}: CommitFileDeletionsProps) => {\n if (count <= 0) {\n return null;\n }\n\n return (\n <span className={cn(\"text-destructive-text\", className)} {...props}>\n {children ?? (\n <>\n <MinusIcon className=\"inline-block size-3\" />\n {count}\n </>\n )}\n </span>\n );\n};\n"],"mappings":"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","names":[]}
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import {
3
+ lazyFlowPart
4
+ } from "./chunk-NMVNNO3L.js";
5
+
6
+ // src/toolbar.tsx
7
+ import { Suspense } from "react";
8
+ import { jsx } from "react/jsx-runtime";
9
+ var NodeToolbarImpl = lazyFlowPart((m) => m.Toolbar);
10
+ var NodeToolbar = (props) => (
11
+ // `NodeToolbar` only ever renders inside a `<Canvas>` (it portals out of the
12
+ // node), so the engine chunk is already in cache; it is wrapped anyway because
13
+ // it is independently barrel-exported.
14
+ /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(NodeToolbarImpl, { "data-slot": "node-toolbar", ...props }) })
15
+ );
16
+
17
+ export {
18
+ NodeToolbar
19
+ };
20
+ //# sourceMappingURL=chunk-UPXSLILN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/toolbar.tsx"],"sourcesContent":["\"use client\";\n\nimport type { NodeToolbar as FlowNodeToolbar } from \"@xyflow/react\";\nimport type { ComponentProps } from \"react\";\nimport { Suspense } from \"react\";\n\nimport { lazyFlowPart } from \"./_flow-lazy\";\n\nexport type NodeToolbarProps = ComponentProps<typeof FlowNodeToolbar>;\n\n/** React Flow lives behind a dynamic import — see `_flow-lazy.ts` and ADR 0019. */\nconst NodeToolbarImpl = lazyFlowPart<NodeToolbarProps>((m) => m.Toolbar);\n\n/**\n * The floating control strip attached to a selected canvas NODE — it portals out\n * of the node and follows it, and it is meaningless outside a `<Canvas>`.\n *\n * Named `NodeToolbar` (after the React Flow primitive it wraps) because\n * `Toolbar` now means the general-purpose WAI-ARIA toolbar in\n * `@elabs-ai/components-ui`: a keyboard row with a roving tabindex.\n * The two solve unrelated problems, and the collision made \"use the Toolbar\"\n * ambiguous at every call site.\n */\nexport const NodeToolbar = (props: NodeToolbarProps) => (\n // `NodeToolbar` only ever renders inside a `<Canvas>` (it portals out of the\n // node), so the engine chunk is already in cache; it is wrapped anyway because\n // it is independently barrel-exported.\n <Suspense fallback={null}>\n {/* The strip portals out of the node it belongs to, so it is nowhere near\n that node in the DOM — a stable selector is the only way a consumer or a\n test can find it. Overridable, like every other `data-slot`. */}\n <NodeToolbarImpl data-slot=\"node-toolbar\" {...props} />\n </Suspense>\n);\n"],"mappings":";;;;;;AAIA,SAAS,gBAAgB;AA2BrB;AApBJ,IAAM,kBAAkB,aAA+B,CAAC,MAAM,EAAE,OAAO;AAYhE,IAAM,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA,EAI1B,oBAAC,YAAS,UAAU,MAIlB,8BAAC,mBAAgB,aAAU,gBAAgB,GAAG,OAAO,GACvD;AAAA;","names":[]}
@@ -0,0 +1,92 @@
1
+ "use client";
2
+ import {
3
+ getStreamdownPluginsKey,
4
+ useStreamdownMermaidOptions,
5
+ useStreamdownPlugins,
6
+ useStreamdownTranslations
7
+ } from "./chunk-PQBF6ZIQ.js";
8
+ import {
9
+ stripSanitizerOverrides,
10
+ warnOnTrustedPluginSlots
11
+ } from "./chunk-DZW6LM22.js";
12
+
13
+ // src/markdown-view.tsx
14
+ import {
15
+ ProseBlockquote,
16
+ ProseHeading,
17
+ ProseInlineCode,
18
+ ProseLink,
19
+ ProseList,
20
+ ProseListItem,
21
+ ProseText
22
+ } from "@elabs-ai/components-ui";
23
+ import { cn } from "@elabs-ai/components-ui/lib/cn";
24
+ import { useMemo } from "react";
25
+ import { Streamdown } from "streamdown";
26
+ import { jsx } from "react/jsx-runtime";
27
+ var MAX_HEADING_LEVEL = 6;
28
+ var clampHeadingLevel = (level) => Math.min(MAX_HEADING_LEVEL, Math.max(1, level));
29
+ function buildProseComponents(baseHeadingLevel) {
30
+ const heading = (markdownLevel) => ({ node: _node, ...props }) => /* @__PURE__ */ jsx(ProseHeading, { level: clampHeadingLevel(markdownLevel + baseHeadingLevel - 1), ...props });
31
+ return {
32
+ h1: heading(1),
33
+ h2: heading(2),
34
+ h3: heading(3),
35
+ h4: heading(4),
36
+ h5: heading(5),
37
+ h6: heading(6),
38
+ p: ({ node: _node, ...props }) => /* @__PURE__ */ jsx(ProseText, { ...props }),
39
+ a: ({ node: _node, ...props }) => /* @__PURE__ */ jsx(ProseLink, { ...props }),
40
+ // `ref` is stripped: ProseList's intersection ref type (ul & ol) is
41
+ // narrower than the per-element ref react-markdown passes.
42
+ ul: ({ node: _node, ref: _ref, ...props }) => /* @__PURE__ */ jsx(ProseList, { ...props }),
43
+ ol: ({ node: _node, ref: _ref, ...props }) => /* @__PURE__ */ jsx(ProseList, { ordered: true, ...props }),
44
+ li: ({ node: _node, ...props }) => /* @__PURE__ */ jsx(ProseListItem, { ...props }),
45
+ blockquote: ({ node: _node, ...props }) => /* @__PURE__ */ jsx(ProseBlockquote, { ...props }),
46
+ code: ({ node: _node, className, ...props }) => /\blanguage-/.test(className ?? "") ? /* @__PURE__ */ jsx("code", { className, ...props }) : /* @__PURE__ */ jsx(ProseInlineCode, { className, ...props })
47
+ };
48
+ }
49
+ var MarkdownView = ({
50
+ baseHeadingLevel = 1,
51
+ className,
52
+ children,
53
+ components: componentOverrides,
54
+ plugins: pluginOverrides,
55
+ ...props
56
+ }) => {
57
+ stripSanitizerOverrides(props);
58
+ const internalComponents = useMemo(
59
+ () => buildProseComponents(baseHeadingLevel),
60
+ [baseHeadingLevel]
61
+ );
62
+ const components = useMemo(
63
+ () => ({ ...internalComponents, ...componentOverrides }),
64
+ [internalComponents, componentOverrides]
65
+ );
66
+ const translations = useStreamdownTranslations();
67
+ const internalPlugins = useStreamdownPlugins(typeof children === "string" ? children : "");
68
+ const plugins = useMemo(() => {
69
+ warnOnTrustedPluginSlots(pluginOverrides, internalPlugins);
70
+ return { ...internalPlugins, ...pluginOverrides };
71
+ }, [internalPlugins, pluginOverrides]);
72
+ const mermaidOptions = useStreamdownMermaidOptions();
73
+ return /* @__PURE__ */ jsx(
74
+ Streamdown,
75
+ {
76
+ "data-slot": "markdown-view",
77
+ className: cn("space-y-3 [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", className),
78
+ components,
79
+ plugins,
80
+ translations,
81
+ mermaid: mermaidOptions,
82
+ ...props,
83
+ children
84
+ },
85
+ getStreamdownPluginsKey(internalPlugins)
86
+ );
87
+ };
88
+
89
+ export {
90
+ MarkdownView
91
+ };
92
+ //# sourceMappingURL=chunk-V4DORGWJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/markdown-view.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * MarkdownView — the branded READ-ONLY markdown renderer (#193, research 04 §5).\n *\n * Renders a markdown *document* as a document — never as Shiki source (that\n * was the ASSET-2 defect: `CodeBlock code={…} language=\"markdown\"`). Built on\n * the EXISTING `streamdown` dependency (no new heavy dep), but unlike the\n * streaming `MessageResponse` it maps the element tree onto the promoted\n * `Prose*` primitives from `@elabs-ai/components-ui` via a `components` map.\n *\n * What is SHARED is the `Prose*` set — plus the Streamdown locale bridge in\n * `_streamdown-i18n` and `ui`'s `streamdown-translations` — NOT the renderer and\n * NOT the element map. The wording this docblock used to carry (\"one source-owned\n * prose set for chat answers, the editor preview and this view\") kept being read\n * as \"one renderer\", and it never meant that. Three branded document renderers\n * ship, and their element MAPS stay per-surface on purpose:\n * - this view — `baseHeadingLevel` for a constrained rung, and a sanitiser\n * chain locked at the type level AND at runtime;\n * - `@elabs-ai/components-editor`'s `MarkdownPreview` — the brand `:::card` /\n * `:::callout` / `::metric` / `:::timeline` dialect, and every standard\n * element wrapped to attach `data-sourcepos`, the ghost-diff wash and the\n * search wash, with slug ids and a heading-action slot on headings;\n * - `@elabs-ai/components-viewer`'s markdown adapter — a file the app did not\n * write, so no plugins and no streaming.\n * `ai`, `editor` and `viewer` are layer-2 leaves that may not import one\n * another, so the half that COULD move down already has; and `streamdown` must\n * never follow it into `ui` — see the rule stated in\n * `packages/ui/src/lib/streamdown-translations.ts` — or every consumer of every\n * foundation component would carry it. Re-litigated and re-ratified 2026-09-03:\n * the three maps are the decision, not an unpaid debt.\n *\n * `baseHeadingLevel` is the constrained-rung seam (research 04 §5 / 09 §G.2):\n * inside a narrow rail pass `baseHeadingLevel={2}` so a document `#` renders\n * at the `title` rung, not the reading-scale h1 — never \"biggest text on\n * screen\" inside a 20rem panel.\n */\nimport {\n ProseBlockquote,\n ProseHeading,\n ProseInlineCode,\n ProseLink,\n ProseList,\n ProseListItem,\n ProseText,\n type ProseHeadingLevel,\n} from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport { stripSanitizerOverrides, warnOnTrustedPluginSlots } from \"./_streamdown-safety\";\nimport {\n getStreamdownPluginsKey,\n useStreamdownMermaidOptions,\n useStreamdownPlugins,\n useStreamdownTranslations,\n} from \"./_streamdown-i18n\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\nimport { Streamdown } from \"streamdown\";\n\ntype StreamdownComponents = NonNullable<ComponentProps<typeof Streamdown>[\"components\"]>;\ntype StreamdownPlugins = ComponentProps<typeof Streamdown>[\"plugins\"];\n\nconst MAX_HEADING_LEVEL = 6;\n\nconst clampHeadingLevel = (level: number): ProseHeadingLevel =>\n Math.min(MAX_HEADING_LEVEL, Math.max(1, level)) as ProseHeadingLevel;\n\n/**\n * Map the markdown element tree onto the Prose* primitives. Fenced code blocks\n * (className `language-*`) stay with the streamdown `code` plugin (Shiki);\n * only INLINE code re-maps to `ProseInlineCode`.\n */\nfunction buildProseComponents(baseHeadingLevel: ProseHeadingLevel): StreamdownComponents {\n const heading =\n (markdownLevel: number): StreamdownComponents[\"h1\"] =>\n ({ node: _node, ...props }) => (\n <ProseHeading level={clampHeadingLevel(markdownLevel + baseHeadingLevel - 1)} {...props} />\n );\n return {\n h1: heading(1),\n h2: heading(2),\n h3: heading(3),\n h4: heading(4),\n h5: heading(5),\n h6: heading(6),\n p: ({ node: _node, ...props }) => <ProseText {...props} />,\n a: ({ node: _node, ...props }) => <ProseLink {...props} />,\n // `ref` is stripped: ProseList's intersection ref type (ul & ol) is\n // narrower than the per-element ref react-markdown passes.\n ul: ({ node: _node, ref: _ref, ...props }) => <ProseList {...props} />,\n ol: ({ node: _node, ref: _ref, ...props }) => <ProseList ordered {...props} />,\n li: ({ node: _node, ...props }) => <ProseListItem {...props} />,\n blockquote: ({ node: _node, ...props }) => <ProseBlockquote {...props} />,\n code: ({ node: _node, className, ...props }) =>\n /\\blanguage-/.test(className ?? \"\") ? (\n <code className={className} {...props} />\n ) : (\n <ProseInlineCode className={className} {...props} />\n ),\n };\n}\n\nexport interface MarkdownViewProps extends Omit<\n ComponentProps<typeof Streamdown>,\n \"components\" | \"plugins\" | \"rehypePlugins\"\n> {\n /**\n * The prose level a markdown `#` maps to; deeper headings shift with it\n * (capped at 6). Default `1` (the full reading scale). Pass `2` in narrow\n * embeds (a context rail) so headings stay on the constrained rung.\n */\n baseHeadingLevel?: ProseHeadingLevel;\n /**\n * Per-element renderer overrides, MERGED over the internal Prose* map\n * (#10) — a consumer entry wins for its key; every key the consumer does\n * NOT set keeps rendering through `buildProseComponents()`. This is the\n * seam for rendering inline citations: override `a` (or a custom node\n * type) to swap a `[1](url)`-style marker for an `InlineCitation` chip\n * while headings/lists/etc. keep the branded prose styling.\n *\n * Deliberately a MERGE, not a replace: sanitisation is unaffected either\n * way (see `plugins` below), but a wholesale replace would silently drop\n * the branded styling from every element the consumer didn't think to\n * re-declare — a citation override should not have to also re-implement\n * headings/lists/code to keep them on-brand.\n *\n * **Known constraint: a `components` change alone does not force a\n * re-render of already-rendered markdown (#10).** Streamdown memoizes on\n * `children`/`plugins`/theme/etc but NOT on `components`\n * (`streamdown@2.5.0`'s top-level `memo` comparator omits it), so if the\n * SAME markdown string is still current when an override's closed-over\n * data changes — e.g. an inline-citation chip that resolves its title\n * asynchronously — the new render function is captured but nothing\n * schedules Streamdown to call it again. Don't rely on a `components`\n * closure to reflect state that arrives after the initial render; instead\n * have the overriding component read that state itself (a shared context,\n * a store keyed by citation id, or an internal `useState`/subscription\n * inside the override) so IT re-renders independently of `MarkdownView`'s\n * own render pass — the pattern `InlineCitation`/`InlineCitationCard`\n * already use.\n */\n components?: StreamdownComponents;\n /**\n * Streamdown plugin-slot overrides (`cjk`/`code`/`math`/`mermaid`/\n * `renderers`), MERGED per key over the internal defaults (the reactive,\n * brand-token-derived `code` plugin and i18n-aware `cjk`/`math`/`mermaid`\n * set — see `_streamdown-i18n.ts`).\n *\n * **This narrow `plugins` prop can only APPEND — it can never displace\n * Streamdown's default `rehypePlugins` chain** (`rehype-raw` →\n * `rehype-sanitize` → `rehype-harden`). `MarkdownView` never sets\n * `rehypePlugins` itself, and nothing in `PluginConfig` removes or replaces\n * a member of that pipeline, so the sanitiser cannot be turned off through\n * this prop. But two of the five slots are **not** upstream of it and must\n * be treated as trusted code:\n * - **`math.rehypePlugin` runs AFTER `rehype-sanitize`/`rehype-harden`**\n * (appended to the end of the rehype pipeline, 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\n * `dangerouslySetInnerHTML` (streamdown's only such sink). brand-ui's own\n * `useStreamdownPlugins()` default pins `securityLevel: \"strict\"`\n * (`_lazy-mermaid.ts`); a replacement `mermaid` plugin must sanitise its\n * own SVG output the same way.\n * - `cjk` (remark-stage only — its output is re-sanitised downstream by\n * the rehype pipeline like any other remark result), `code` (feeds only\n * `shikiTheme`, no HTML injection) and `renderers` (ordinary React\n * components rendered with the fenced block's raw `code` string as a\n * `string` prop, the same trusted-component boundary as a `components`\n * override) do not bypass sanitisation.\n *\n * **`rehypePlugins` is NOT exposed on this component (#36, fixed).** Unlike\n * `plugins`, a caller-supplied `rehypePlugins` array would REPLACE\n * Streamdown's default rehype pipeline wholesale rather than extending it,\n * silently dropping `rehype-raw`/`rehype-sanitize`/`rehype-harden` and\n * letting a plain markdown string execute script in the host page — so\n * `MarkdownViewProps` `Omit`s it at the type level AND\n * `stripSanitizerOverrides()` deletes it at runtime before the `{...props}`\n * spread below, even if a JS consumer or a cast reaches this component with\n * it set. If you need to widen sanitisation, use\n * `allowedTags`/`literalTagContent`, which MERGE into the sanitize schema\n * instead of replacing the pipeline. See\n * `packages/ai/src/_streamdown-safety.ts`.\n *\n * **`remarkPlugins` IS supported** (PR #74 review, round 1 — the original\n * #36 fix over-reached and removed it too). The remark stage runs strictly\n * upstream of the rehype chain, and Streamdown builds its rehype list\n * without reading `remarkPlugins`, so everything a remark plugin emits is\n * still sanitised downstream — measured across raw-`html` mdast nodes,\n * `data.hName`/`hChildren` hast elements, `hProperties` event handlers,\n * `javascript:` link URLs and smuggled `raw` hast children. Note the\n * ordinary (non-security) footgun: your array REPLACES Streamdown's own\n * remark defaults (`remark-gfm`, `codeMeta`), so spread\n * `Object.values(defaultRemarkPlugins)` from `streamdown` back in if you\n * want to keep GFM tables/strikethrough.\n */\n plugins?: StreamdownPlugins;\n}\n\nexport const MarkdownView = ({\n baseHeadingLevel = 1,\n className,\n children,\n components: componentOverrides,\n plugins: pluginOverrides,\n ...props\n}: MarkdownViewProps) => {\n // Streamdown installs [rehypeRaw, rehypeSanitize, harden] as the DEFAULT VALUE of\n // `rehypePlugins`; a supplied array REPLACES it. This component renders untrusted\n // model output, so the chain is not overridable. Widen with `allowedTags` /\n // `literalTagContent`, which merge into the sanitize schema. See issue #36.\n // `remarkPlugins` is deliberately left alone — it runs upstream of the rehype\n // chain and cannot bypass it (PR #74 review; see `_streamdown-safety.ts`).\n stripSanitizerOverrides(props);\n const internalComponents = useMemo(\n () => buildProseComponents(baseHeadingLevel),\n [baseHeadingLevel],\n );\n // Consumer entries win per key; every other key falls through to the\n // internal Prose* map — see the `components` prop doc above.\n const components = useMemo(\n () => ({ ...internalComponents, ...componentOverrides }),\n [internalComponents, componentOverrides],\n );\n // Streamdown's own chrome (code copy, table menus) reads the locale seam (#310).\n // Spread AFTER so an explicit `translations` prop still wins (ADR 0017).\n const translations = useStreamdownTranslations();\n // Brand-token-derived `code` plugin, not the package's static github-*\n // default (#315 follow-up) — re-derives when the active theme changes.\n // `math`/`cjk` are lazy-loaded off the raw markdown source (#perf-5, see\n // `_streamdown-i18n.ts`) — pass `children` so they load only when this\n // view actually needs them.\n const internalPlugins = useStreamdownPlugins(typeof children === \"string\" ? children : \"\");\n // Same per-key merge as `components` — see the `plugins` prop doc above.\n // `math.rehypePlugin`/`mermaid` are the two slots that land in the DOM after\n // (or outside) the sanitiser chain, so replacing one is a TRUSTED-CODE\n // decision. The runtime half of that documented boundary is a dev warning —\n // the plugin still runs; stripping it would break the legitimate use (#76).\n const plugins = useMemo(() => {\n warnOnTrustedPluginSlots(pluginOverrides, internalPlugins);\n return { ...internalPlugins, ...pluginOverrides };\n }, [internalPlugins, pluginOverrides]);\n // The TOP-LEVEL Streamdown `mermaid` prop (distinct from `plugins.mermaid`\n // above) — catches a failed diagram render, including a missing `mermaid`\n // optional peer (issue #33). See `_streamdown-i18n.ts`.\n const mermaidOptions = useStreamdownMermaidOptions();\n return (\n <Streamdown\n // Forces a remount the first time the lazy math/cjk slot resolves —\n // see `getStreamdownPluginsKey`'s doc in `_streamdown-i18n.ts` for why.\n key={getStreamdownPluginsKey(internalPlugins)}\n data-slot=\"markdown-view\"\n className={cn(\"space-y-3 [&>*:first-child]:mt-0 [&>*:last-child]:mb-0\", className)}\n components={components}\n plugins={plugins}\n translations={translations}\n mermaid={mermaidOptions}\n {...props}\n >\n {children}\n </Streamdown>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAqCA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,UAAU;AASnB,SAAS,eAAe;AACxB,SAAS,kBAAkB;AAmBrB;AAdN,IAAM,oBAAoB;AAE1B,IAAM,oBAAoB,CAAC,UACzB,KAAK,IAAI,mBAAmB,KAAK,IAAI,GAAG,KAAK,CAAC;AAOhD,SAAS,qBAAqB,kBAA2D;AACvF,QAAM,UACJ,CAAC,kBACD,CAAC,EAAE,MAAM,OAAO,GAAG,MAAM,MACvB,oBAAC,gBAAa,OAAO,kBAAkB,gBAAgB,mBAAmB,CAAC,GAAI,GAAG,OAAO;AAE7F,SAAO;AAAA,IACL,IAAI,QAAQ,CAAC;AAAA,IACb,IAAI,QAAQ,CAAC;AAAA,IACb,IAAI,QAAQ,CAAC;AAAA,IACb,IAAI,QAAQ,CAAC;AAAA,IACb,IAAI,QAAQ,CAAC;AAAA,IACb,IAAI,QAAQ,CAAC;AAAA,IACb,GAAG,CAAC,EAAE,MAAM,OAAO,GAAG,MAAM,MAAM,oBAAC,aAAW,GAAG,OAAO;AAAA,IACxD,GAAG,CAAC,EAAE,MAAM,OAAO,GAAG,MAAM,MAAM,oBAAC,aAAW,GAAG,OAAO;AAAA;AAAA;AAAA,IAGxD,IAAI,CAAC,EAAE,MAAM,OAAO,KAAK,MAAM,GAAG,MAAM,MAAM,oBAAC,aAAW,GAAG,OAAO;AAAA,IACpE,IAAI,CAAC,EAAE,MAAM,OAAO,KAAK,MAAM,GAAG,MAAM,MAAM,oBAAC,aAAU,SAAO,MAAE,GAAG,OAAO;AAAA,IAC5E,IAAI,CAAC,EAAE,MAAM,OAAO,GAAG,MAAM,MAAM,oBAAC,iBAAe,GAAG,OAAO;AAAA,IAC7D,YAAY,CAAC,EAAE,MAAM,OAAO,GAAG,MAAM,MAAM,oBAAC,mBAAiB,GAAG,OAAO;AAAA,IACvE,MAAM,CAAC,EAAE,MAAM,OAAO,WAAW,GAAG,MAAM,MACxC,cAAc,KAAK,aAAa,EAAE,IAChC,oBAAC,UAAK,WAAuB,GAAG,OAAO,IAEvC,oBAAC,mBAAgB,WAAuB,GAAG,OAAO;AAAA,EAExD;AACF;AAoGO,IAAM,eAAe,CAAC;AAAA,EAC3B,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,GAAG;AACL,MAAyB;AAOvB,0BAAwB,KAAK;AAC7B,QAAM,qBAAqB;AAAA,IACzB,MAAM,qBAAqB,gBAAgB;AAAA,IAC3C,CAAC,gBAAgB;AAAA,EACnB;AAGA,QAAM,aAAa;AAAA,IACjB,OAAO,EAAE,GAAG,oBAAoB,GAAG,mBAAmB;AAAA,IACtD,CAAC,oBAAoB,kBAAkB;AAAA,EACzC;AAGA,QAAM,eAAe,0BAA0B;AAM/C,QAAM,kBAAkB,qBAAqB,OAAO,aAAa,WAAW,WAAW,EAAE;AAMzF,QAAM,UAAU,QAAQ,MAAM;AAC5B,6BAAyB,iBAAiB,eAAe;AACzD,WAAO,EAAE,GAAG,iBAAiB,GAAG,gBAAgB;AAAA,EAClD,GAAG,CAAC,iBAAiB,eAAe,CAAC;AAIrC,QAAM,iBAAiB,4BAA4B;AACnD,SACE;AAAA,IAAC;AAAA;AAAA,MAIC,aAAU;AAAA,MACV,WAAW,GAAG,0DAA0D,SAAS;AAAA,MACjF;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACR,GAAG;AAAA,MAEH;AAAA;AAAA,IATI,wBAAwB,eAAe;AAAA,EAU9C;AAEJ;","names":[]}
@@ -0,0 +1,80 @@
1
+ "use client";
2
+
3
+ // src/image.tsx
4
+ import { Skeleton, useLocale } from "@elabs-ai/components-ui";
5
+ import { cn } from "@elabs-ai/components-ui/lib/cn";
6
+ import { ImageOff } from "lucide-react";
7
+ import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ var Image = forwardRef(function Image2({
10
+ base64,
11
+ uint8Array: _uint8Array,
12
+ mediaType,
13
+ className,
14
+ showSkeleton,
15
+ onLoad,
16
+ onError,
17
+ width,
18
+ height,
19
+ alt,
20
+ ...props
21
+ }, forwardedRef) {
22
+ const { t } = useLocale();
23
+ const shouldSkeleton = showSkeleton ?? Boolean(width && height);
24
+ const [loaded, setLoaded] = useState(false);
25
+ const [failed, setFailed] = useState(false);
26
+ const imgRef = useRef(null);
27
+ useImperativeHandle(forwardedRef, () => imgRef.current);
28
+ const pending = shouldSkeleton && !loaded && !failed;
29
+ const [announce, setAnnounce] = useState(false);
30
+ useEffect(() => setAnnounce(pending), [pending]);
31
+ useEffect(() => {
32
+ if (imgRef.current?.complete) setLoaded(true);
33
+ }, []);
34
+ if (failed) {
35
+ return /* @__PURE__ */ jsx(
36
+ "span",
37
+ {
38
+ className: cn(
39
+ "flex flex-col items-center justify-center gap-1 rounded-md bg-muted text-muted-foreground",
40
+ className
41
+ ),
42
+ style: { height, width },
43
+ ...alt ? { role: "img", "aria-label": alt } : { "aria-hidden": true },
44
+ children: /* @__PURE__ */ jsx(ImageOff, { className: "size-6", "aria-hidden": "true" })
45
+ }
46
+ );
47
+ }
48
+ const img = /* @__PURE__ */ jsx(
49
+ "img",
50
+ {
51
+ ...props,
52
+ ref: imgRef,
53
+ alt: alt ?? "",
54
+ height,
55
+ width,
56
+ className: cn("h-auto max-w-full overflow-hidden rounded-md", className),
57
+ src: `data:${mediaType};base64,${base64}`,
58
+ onLoad: (event) => {
59
+ setLoaded(true);
60
+ onLoad?.(event);
61
+ },
62
+ onError: (event) => {
63
+ setFailed(true);
64
+ onError?.(event);
65
+ }
66
+ }
67
+ );
68
+ if (!shouldSkeleton) return img;
69
+ return /* @__PURE__ */ jsxs("span", { className: "relative inline-block max-w-full", style: { height, width }, children: [
70
+ /* @__PURE__ */ jsx("span", { className: "sr-only", role: "status", "aria-live": "polite", children: announce ? t("loading") : "" }),
71
+ pending ? /* @__PURE__ */ jsx(Skeleton, { className: "absolute inset-0 size-full rounded-md" }) : null,
72
+ img
73
+ ] });
74
+ });
75
+ Image.displayName = "Image";
76
+
77
+ export {
78
+ Image
79
+ };
80
+ //# sourceMappingURL=chunk-V6E5DYZD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/image.tsx"],"sourcesContent":["\"use client\";\n\nimport { Skeleton, useLocale } from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport type { Experimental_GeneratedImage } from \"ai\";\nimport { ImageOff } from \"lucide-react\";\nimport type { ImgHTMLAttributes } from \"react\";\nimport { forwardRef, useEffect, useImperativeHandle, useRef, useState } from \"react\";\n\nexport type ImageProps = Experimental_GeneratedImage &\n Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\"> & {\n /**\n * Show a Skeleton placeholder (loading-states.md) until the img element\n * finishes decoding, so the base64 payload does not pop in. Requires\n * explicit `width`+`height` so the reserved box matches the final size\n * (interaction-guidelines.md Images section — prevents CLS); without\n * both there is no box to reserve, so the default is `false` in that\n * case rather than mounting a skeleton that collapses to nothing.\n * @default Boolean(width && height)\n */\n showSkeleton?: boolean;\n };\n\n/** `<img>` wrapper for an AI-SDK generated image, with a decode-aware skeleton. */\nexport const Image = forwardRef<HTMLImageElement, ImageProps>(function Image(\n {\n base64,\n uint8Array: _uint8Array,\n mediaType,\n className,\n showSkeleton,\n onLoad,\n onError,\n width,\n height,\n alt,\n ...props\n },\n forwardedRef,\n) {\n const { t } = useLocale();\n const shouldSkeleton = showSkeleton ?? Boolean(width && height);\n const [loaded, setLoaded] = useState(false);\n const [failed, setFailed] = useState(false);\n const imgRef = useRef<HTMLImageElement>(null);\n useImperativeHandle(forwardedRef, () => imgRef.current as HTMLImageElement);\n\n const pending = shouldSkeleton && !loaded && !failed;\n\n // The live region must exist BEFORE its text appears (ARIA22), so it is\n // always mounted (while a skeleton can render at all) and its label is set\n // one tick later via this effect.\n const [announce, setAnnounce] = useState(false);\n useEffect(() => setAnnounce(pending), [pending]);\n\n // A cached / instant data-URI decode can finish before React attaches\n // `onLoad` — read `complete` once mounted (gallery.tsx's GalleryImg has the\n // same guard).\n useEffect(() => {\n if (imgRef.current?.complete) setLoaded(true);\n }, []);\n\n if (failed) {\n return (\n <span\n className={cn(\n \"flex flex-col items-center justify-center gap-1 rounded-md bg-muted text-muted-foreground\",\n className,\n )}\n style={{ height, width }}\n {...(alt ? { role: \"img\", \"aria-label\": alt } : { \"aria-hidden\": true })}\n >\n <ImageOff className=\"size-6\" aria-hidden=\"true\" />\n </span>\n );\n }\n\n const img = (\n <img\n {...props}\n ref={imgRef}\n alt={alt ?? \"\"}\n height={height}\n width={width}\n className={cn(\"h-auto max-w-full overflow-hidden rounded-md\", className)}\n src={`data:${mediaType};base64,${base64}`}\n onLoad={(event) => {\n setLoaded(true);\n onLoad?.(event);\n }}\n onError={(event) => {\n setFailed(true);\n onError?.(event);\n }}\n />\n );\n\n // No skeleton to reserve a box for — render the bare <img> exactly as\n // before this feature landed (a `className` like \"w-full\" keeps resolving\n // against the real parent, not a shrink-to-fit wrapper), and mount no\n // (permanently empty) live region.\n if (!shouldSkeleton) return img;\n\n return (\n <span className=\"relative inline-block max-w-full\" style={{ height, width }}>\n <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {announce ? t(\"loading\") : \"\"}\n </span>\n {pending ? <Skeleton className=\"absolute inset-0 size-full rounded-md\" /> : null}\n {img}\n </span>\n );\n});\n\nImage.displayName = \"Image\";\n"],"mappings":";;;AAEA,SAAS,UAAU,iBAAiB;AACpC,SAAS,UAAU;AAEnB,SAAS,gBAAgB;AAEzB,SAAS,YAAY,WAAW,qBAAqB,QAAQ,gBAAgB;AAiErE,cAgCJ,YAhCI;AAhDD,IAAM,QAAQ,WAAyC,SAASA,OACrE;AAAA,EACE;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GACA,cACA;AACA,QAAM,EAAE,EAAE,IAAI,UAAU;AACxB,QAAM,iBAAiB,gBAAgB,QAAQ,SAAS,MAAM;AAC9D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,SAAS,OAAyB,IAAI;AAC5C,sBAAoB,cAAc,MAAM,OAAO,OAA2B;AAE1E,QAAM,UAAU,kBAAkB,CAAC,UAAU,CAAC;AAK9C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,YAAU,MAAM,YAAY,OAAO,GAAG,CAAC,OAAO,CAAC;AAK/C,YAAU,MAAM;AACd,QAAI,OAAO,SAAS,SAAU,WAAU,IAAI;AAAA,EAC9C,GAAG,CAAC,CAAC;AAEL,MAAI,QAAQ;AACV,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QACA,OAAO,EAAE,QAAQ,MAAM;AAAA,QACtB,GAAI,MAAM,EAAE,MAAM,OAAO,cAAc,IAAI,IAAI,EAAE,eAAe,KAAK;AAAA,QAEtE,8BAAC,YAAS,WAAU,UAAS,eAAY,QAAO;AAAA;AAAA,IAClD;AAAA,EAEJ;AAEA,QAAM,MACJ;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,KAAK;AAAA,MACL,KAAK,OAAO;AAAA,MACZ;AAAA,MACA;AAAA,MACA,WAAW,GAAG,gDAAgD,SAAS;AAAA,MACvE,KAAK,QAAQ,SAAS,WAAW,MAAM;AAAA,MACvC,QAAQ,CAAC,UAAU;AACjB,kBAAU,IAAI;AACd,iBAAS,KAAK;AAAA,MAChB;AAAA,MACA,SAAS,CAAC,UAAU;AAClB,kBAAU,IAAI;AACd,kBAAU,KAAK;AAAA,MACjB;AAAA;AAAA,EACF;AAOF,MAAI,CAAC,eAAgB,QAAO;AAE5B,SACE,qBAAC,UAAK,WAAU,oCAAmC,OAAO,EAAE,QAAQ,MAAM,GACxE;AAAA,wBAAC,UAAK,WAAU,WAAU,MAAK,UAAS,aAAU,UAC/C,qBAAW,EAAE,SAAS,IAAI,IAC7B;AAAA,IACC,UAAU,oBAAC,YAAS,WAAU,yCAAwC,IAAK;AAAA,IAC3E;AAAA,KACH;AAEJ,CAAC;AAED,MAAM,cAAc;","names":["Image"]}
@@ -0,0 +1,96 @@
1
+ "use client";
2
+
3
+ // src/session-status-bar.tsx
4
+ import { cn, useLocale } from "@elabs-ai/components-ui";
5
+ import { Cpu, Folder, GitBranch, Loader2Icon, PlugZapIcon } from "lucide-react";
6
+ import { forwardRef } from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ var SessionStatusBarSegment = ({
9
+ icon: Icon,
10
+ slot,
11
+ value
12
+ }) => /* @__PURE__ */ jsxs("span", { className: "inline-flex min-w-0 items-center gap-1.5", "data-slot": slot, children: [
13
+ /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true", className: "size-3.5 shrink-0" }),
14
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: value })
15
+ ] });
16
+ var SessionStatusBar = forwardRef(
17
+ function SessionStatusBar2({ workspace, branch, model, connections, children, className, ...props }, ref) {
18
+ const { formatNumber, t } = useLocale();
19
+ const hasContent = Boolean(workspace ?? branch ?? model ?? connections ?? children);
20
+ if (!hasContent) {
21
+ return null;
22
+ }
23
+ const connectionsAnnouncement = connections ? connections.connecting ? t("ai.sessionStatusBar.connecting") : t("ai.sessionStatusBar.connections", {
24
+ connected: connections.connected,
25
+ total: connections.total
26
+ }) : void 0;
27
+ return /* @__PURE__ */ jsxs(
28
+ "div",
29
+ {
30
+ ref,
31
+ className: cn(
32
+ "flex w-full items-center gap-4 border-t bg-surface-muted px-3 py-1.5 text-meta text-muted-foreground",
33
+ className
34
+ ),
35
+ "data-slot": "session-status-bar",
36
+ ...props,
37
+ children: [
38
+ workspace ? /* @__PURE__ */ jsx(
39
+ SessionStatusBarSegment,
40
+ {
41
+ icon: Folder,
42
+ slot: "session-status-bar-workspace",
43
+ value: workspace
44
+ }
45
+ ) : null,
46
+ branch ? /* @__PURE__ */ jsx(
47
+ SessionStatusBarSegment,
48
+ {
49
+ icon: GitBranch,
50
+ slot: "session-status-bar-branch",
51
+ value: branch
52
+ }
53
+ ) : null,
54
+ model ? /* @__PURE__ */ jsx(SessionStatusBarSegment, { icon: Cpu, slot: "session-status-bar-model", value: model }) : null,
55
+ connections ? /* @__PURE__ */ jsxs(
56
+ "span",
57
+ {
58
+ "aria-live": "polite",
59
+ className: "inline-flex shrink-0 items-center gap-1.5",
60
+ "data-slot": "session-status-bar-connections",
61
+ role: "status",
62
+ children: [
63
+ connections.connecting ? /* @__PURE__ */ jsx(
64
+ Loader2Icon,
65
+ {
66
+ "aria-hidden": "true",
67
+ className: "size-3.5 shrink-0 animate-spin motion-reduce:animate-none"
68
+ }
69
+ ) : /* @__PURE__ */ jsx(PlugZapIcon, { "aria-hidden": "true", className: "size-3.5 shrink-0" }),
70
+ /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "tabular-nums", children: [
71
+ formatNumber(connections.connected),
72
+ "/",
73
+ formatNumber(connections.total)
74
+ ] }),
75
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: connectionsAnnouncement })
76
+ ]
77
+ }
78
+ ) : null,
79
+ children ? /* @__PURE__ */ jsx(
80
+ "div",
81
+ {
82
+ className: "ms-auto flex shrink-0 items-center",
83
+ "data-slot": "session-status-bar-context",
84
+ children
85
+ }
86
+ ) : null
87
+ ]
88
+ }
89
+ );
90
+ }
91
+ );
92
+
93
+ export {
94
+ SessionStatusBar
95
+ };
96
+ //# sourceMappingURL=chunk-VLLYKF3P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/session-status-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn, useLocale } from \"@elabs-ai/components-ui\";\nimport { Cpu, Folder, GitBranch, Loader2Icon, PlugZapIcon } from \"lucide-react\";\nimport type { ComponentProps, ComponentType, ReactNode, SVGProps } from \"react\";\nimport { forwardRef } from \"react\";\n\nexport interface SessionStatusBarConnections {\n /** Number of integrations/MCP servers currently connected. */\n connected: number;\n /** Total number of configured integrations/MCP servers. */\n total: number;\n /** Renders a spinner in place of the connection icon while establishing. */\n connecting?: boolean;\n}\n\nexport interface SessionStatusBarProps extends ComponentProps<\"div\"> {\n /** Current workspace/project name. */\n workspace?: string;\n /** Current git branch. */\n branch?: string;\n /** Active model id/label. */\n model?: string;\n /** Integration/MCP connection progress; renders a spinner while connecting. */\n connections?: SessionStatusBarConnections;\n /**\n * Docks another component alongside the ambient segments — most often\n * `<TokenUsage />` (`@elabs-ai/components-ai`), so token usage/cost keeps\n * its one owner (`token-usage.tsx`, tokenlens) instead of being re-implemented\n * here. Rendered flush to the end of the bar.\n */\n children?: ReactNode;\n}\n\ntype SegmentIcon = ComponentType<SVGProps<SVGSVGElement>>;\n\nconst SessionStatusBarSegment = ({\n icon: Icon,\n slot,\n value,\n}: {\n icon: SegmentIcon;\n slot: string;\n value: string;\n}) => (\n <span className=\"inline-flex min-w-0 items-center gap-1.5\" data-slot={slot}>\n <Icon aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n <span className=\"truncate\">{value}</span>\n </span>\n);\n\n/**\n * SessionStatusBar — the ambient session row: workspace, branch, model, and\n * integration-connection progress (#105). Every segment is independently\n * optional and renders only when its prop is supplied; with nothing supplied\n * the bar renders nothing at all, not an empty shell.\n *\n * Docks `Context` (or any other node) via `children` rather than\n * re-implementing token-usage/cost maths — `context.tsx` stays the one owner\n * of that calculation (tokenlens).\n */\nexport const SessionStatusBar = forwardRef<HTMLDivElement, SessionStatusBarProps>(\n function SessionStatusBar(\n { workspace, branch, model, connections, children, className, ...props },\n ref,\n ) {\n const { formatNumber, t } = useLocale();\n const hasContent = Boolean(workspace ?? branch ?? model ?? connections ?? children);\n\n if (!hasContent) {\n return null;\n }\n\n // Computed once and reused for BOTH the connections region's name (for a\n // user who navigates to it deliberately) and its real, non-hidden text\n // content — what a polite announcement actually reads on change. An\n // aria-label alone is NOT that (#155): a live region announces its\n // content, not its own accessible name.\n const connectionsAnnouncement = connections\n ? connections.connecting\n ? t(\"ai.sessionStatusBar.connecting\")\n : t(\"ai.sessionStatusBar.connections\", {\n connected: connections.connected,\n total: connections.total,\n })\n : undefined;\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex w-full items-center gap-4 border-t bg-surface-muted px-3 py-1.5 text-meta text-muted-foreground\",\n className,\n )}\n data-slot=\"session-status-bar\"\n {...props}\n >\n {workspace ? (\n <SessionStatusBarSegment\n icon={Folder}\n slot=\"session-status-bar-workspace\"\n value={workspace}\n />\n ) : null}\n {branch ? (\n <SessionStatusBarSegment\n icon={GitBranch}\n slot=\"session-status-bar-branch\"\n value={branch}\n />\n ) : null}\n {model ? (\n <SessionStatusBarSegment icon={Cpu} slot=\"session-status-bar-model\" value={model} />\n ) : null}\n {connections ? (\n <span\n aria-live=\"polite\"\n className=\"inline-flex shrink-0 items-center gap-1.5\"\n data-slot=\"session-status-bar-connections\"\n role=\"status\"\n >\n {connections.connecting ? (\n <Loader2Icon\n aria-hidden=\"true\"\n className=\"size-3.5 shrink-0 animate-spin motion-reduce:animate-none\"\n />\n ) : (\n <PlugZapIcon aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n )}\n <span aria-hidden=\"true\" className=\"tabular-nums\">\n {formatNumber(connections.connected)}/{formatNumber(connections.total)}\n </span>\n {/* The live region's only NON-hidden text — mirrors\n terminal-status-bar.tsx's aria-hidden-visual +\n sr-only-sentence pair (#155). Without this, every polite\n update announced an empty string: the counter above is\n aria-hidden, so it was the region's ONLY text content.\n Deliberately no `aria-label` here (unlike\n terminal-status-bar.tsx, where the label lives on the OUTER\n bar as a generic region name distinct from any segment's\n content): an explicit `aria-label` here would give this\n span an ACCESSIBLE NAME byte-identical to its announced\n CONTENT, which risks a double announcement (\"Connecting…\n Connecting…\") on ATs that speak a live region's name\n alongside its changed content. Leaving `aria-label` off\n does NOT relocate the name to this text — `role=\"status\"`\n is `nameFrom: author`, so it never falls back to content\n the way e.g. a `button` does. The span simply has no\n accessible name, which is fine: no acceptance criterion\n needs one here, only the announced content does. */}\n <span className=\"sr-only\">{connectionsAnnouncement}</span>\n </span>\n ) : null}\n {children ? (\n <div\n className=\"ms-auto flex shrink-0 items-center\"\n data-slot=\"session-status-bar-context\"\n >\n {children}\n </div>\n ) : null}\n </div>\n );\n },\n);\n"],"mappings":";;;AAEA,SAAS,IAAI,iBAAiB;AAC9B,SAAS,KAAK,QAAQ,WAAW,aAAa,mBAAmB;AAEjE,SAAS,kBAAkB;AAwCzB,SACE,KADF;AATF,IAAM,0BAA0B,CAAC;AAAA,EAC/B,MAAM;AAAA,EACN;AAAA,EACA;AACF,MAKE,qBAAC,UAAK,WAAU,4CAA2C,aAAW,MACpE;AAAA,sBAAC,QAAK,eAAY,QAAO,WAAU,qBAAoB;AAAA,EACvD,oBAAC,UAAK,WAAU,YAAY,iBAAM;AAAA,GACpC;AAaK,IAAM,mBAAmB;AAAA,EAC9B,SAASA,kBACP,EAAE,WAAW,QAAQ,OAAO,aAAa,UAAU,WAAW,GAAG,MAAM,GACvE,KACA;AACA,UAAM,EAAE,cAAc,EAAE,IAAI,UAAU;AACtC,UAAM,aAAa,QAAQ,aAAa,UAAU,SAAS,eAAe,QAAQ;AAElF,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,IACT;AAOA,UAAM,0BAA0B,cAC5B,YAAY,aACV,EAAE,gCAAgC,IAClC,EAAE,mCAAmC;AAAA,MACnC,WAAW,YAAY;AAAA,MACvB,OAAO,YAAY;AAAA,IACrB,CAAC,IACH;AAEJ,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QACA,aAAU;AAAA,QACT,GAAG;AAAA,QAEH;AAAA,sBACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,MAAK;AAAA,cACL,OAAO;AAAA;AAAA,UACT,IACE;AAAA,UACH,SACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,MAAK;AAAA,cACL,OAAO;AAAA;AAAA,UACT,IACE;AAAA,UACH,QACC,oBAAC,2BAAwB,MAAM,KAAK,MAAK,4BAA2B,OAAO,OAAO,IAChF;AAAA,UACH,cACC;AAAA,YAAC;AAAA;AAAA,cACC,aAAU;AAAA,cACV,WAAU;AAAA,cACV,aAAU;AAAA,cACV,MAAK;AAAA,cAEJ;AAAA,4BAAY,aACX;AAAA,kBAAC;AAAA;AAAA,oBACC,eAAY;AAAA,oBACZ,WAAU;AAAA;AAAA,gBACZ,IAEA,oBAAC,eAAY,eAAY,QAAO,WAAU,qBAAoB;AAAA,gBAEhE,qBAAC,UAAK,eAAY,QAAO,WAAU,gBAChC;AAAA,+BAAa,YAAY,SAAS;AAAA,kBAAE;AAAA,kBAAE,aAAa,YAAY,KAAK;AAAA,mBACvE;AAAA,gBAmBA,oBAAC,UAAK,WAAU,WAAW,mCAAwB;AAAA;AAAA;AAAA,UACrD,IACE;AAAA,UACH,WACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,aAAU;AAAA,cAET;AAAA;AAAA,UACH,IACE;AAAA;AAAA;AAAA,IACN;AAAA,EAEJ;AACF;","names":["SessionStatusBar"]}
@@ -0,0 +1,43 @@
1
+ "use client";
2
+
3
+ // src/_lazy-math.ts
4
+ import { useEffect, useState } from "react";
5
+ var MATH_DELIMITER_RE = /\$\$[\s\S]*?\$\$|\$[^\s$][^$\n]*\$|\\\(|\\\)|\\\[|\\\]/;
6
+ function needsMathPlugin(text) {
7
+ return MATH_DELIMITER_RE.test(text);
8
+ }
9
+ var cachedPlugin;
10
+ var loadPromise;
11
+ function loadMathPlugin() {
12
+ loadPromise ??= import("@streamdown/math").then((mod) => {
13
+ cachedPlugin = mod.math;
14
+ return cachedPlugin;
15
+ });
16
+ return loadPromise;
17
+ }
18
+ var preloadMath = () => {
19
+ void loadMathPlugin();
20
+ };
21
+ function useLazyMathPlugin(text) {
22
+ const needed = needsMathPlugin(text);
23
+ const [plugin, setPlugin] = useState(cachedPlugin);
24
+ useEffect(() => {
25
+ if (!needed || cachedPlugin) return;
26
+ let cancelled = false;
27
+ loadMathPlugin().then((loaded) => {
28
+ if (!cancelled) setPlugin(loaded);
29
+ });
30
+ return () => {
31
+ cancelled = true;
32
+ };
33
+ }, [needed]);
34
+ if (!needed) return void 0;
35
+ return plugin ?? cachedPlugin;
36
+ }
37
+
38
+ export {
39
+ needsMathPlugin,
40
+ preloadMath,
41
+ useLazyMathPlugin
42
+ };
43
+ //# sourceMappingURL=chunk-VLNBTOH6.js.map