@mieweb/ui 0.10.0-dev.3 → 0.10.0-dev.30

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 (498) hide show
  1. package/README.md +4 -4
  2. package/agent/mieweb-ui.instructions.md +90 -1
  3. package/dist/CsvBlock-FX5YNGNE.cjs +17 -0
  4. package/dist/{CsvBlock-ROJCKJDP.cjs.map → CsvBlock-FX5YNGNE.cjs.map} +1 -1
  5. package/dist/CsvBlock-VLMG7GUO.js +8 -0
  6. package/dist/{CsvBlock-UWPMTLE2.js.map → CsvBlock-VLMG7GUO.js.map} +1 -1
  7. package/dist/HtmlPreviewBlock-5JE7L3GR.js +8 -0
  8. package/dist/{HtmlPreviewBlock-ME5U3XNS.js.map → HtmlPreviewBlock-5JE7L3GR.js.map} +1 -1
  9. package/dist/HtmlPreviewBlock-UO37JQ3K.cjs +17 -0
  10. package/dist/{HtmlPreviewBlock-DWFN6EUB.cjs.map → HtmlPreviewBlock-UO37JQ3K.cjs.map} +1 -1
  11. package/dist/Input-yN516s5_.d.cts +3 -0
  12. package/dist/Input-yN516s5_.d.ts +3 -0
  13. package/dist/MermaidBlock-3XHFBAMV.js +8 -0
  14. package/dist/{MermaidBlock-2B6CPD6Y.js.map → MermaidBlock-3XHFBAMV.js.map} +1 -1
  15. package/dist/MermaidBlock-RZ75RPZA.cjs +17 -0
  16. package/dist/{MermaidBlock-D2UC5M55.cjs.map → MermaidBlock-RZ75RPZA.cjs.map} +1 -1
  17. package/dist/SurveyBlock-MUVJ3JUI.js +8 -0
  18. package/dist/{SurveyBlock-4DO62RBT.js.map → SurveyBlock-MUVJ3JUI.js.map} +1 -1
  19. package/dist/SurveyBlock-VH47YXZC.cjs +17 -0
  20. package/dist/{SurveyBlock-4CD4AYMJ.cjs.map → SurveyBlock-VH47YXZC.cjs.map} +1 -1
  21. package/dist/ag-grid.d.cts +142 -1
  22. package/dist/ag-grid.d.ts +142 -1
  23. package/dist/brands/bluehive.cjs +3 -3
  24. package/dist/brands/bluehive.css +3 -0
  25. package/dist/brands/bluehive.js +1 -1
  26. package/dist/brands/index.cjs +14 -14
  27. package/dist/brands/index.js +4 -4
  28. package/dist/{chunk-JYZW2PZS.cjs → chunk-254QK722.cjs} +7 -7
  29. package/dist/chunk-254QK722.cjs.map +1 -0
  30. package/dist/{chunk-VKELAMAZ.js → chunk-2JICT4A2.js} +27 -11
  31. package/dist/chunk-2JICT4A2.js.map +1 -0
  32. package/dist/{chunk-VPWJCJCX.cjs → chunk-35Y4ILCU.cjs} +7 -7
  33. package/dist/{chunk-VPWJCJCX.cjs.map → chunk-35Y4ILCU.cjs.map} +1 -1
  34. package/dist/{chunk-G3JX3UAU.cjs → chunk-3KPDQG5O.cjs} +5 -5
  35. package/dist/{chunk-G3JX3UAU.cjs.map → chunk-3KPDQG5O.cjs.map} +1 -1
  36. package/dist/{chunk-Y5HFM7LO.js → chunk-3RXZWHCU.js} +4 -4
  37. package/dist/{chunk-Y5HFM7LO.js.map → chunk-3RXZWHCU.js.map} +1 -1
  38. package/dist/chunk-3YBS4WUQ.js +52 -0
  39. package/dist/chunk-3YBS4WUQ.js.map +1 -0
  40. package/dist/{chunk-WNJRS7Y7.cjs → chunk-3ZWCIPFT.cjs} +4 -2
  41. package/dist/chunk-3ZWCIPFT.cjs.map +1 -0
  42. package/dist/chunk-4HC2IBOX.js +258 -0
  43. package/dist/chunk-4HC2IBOX.js.map +1 -0
  44. package/dist/chunk-4IS3QCOQ.cjs +453 -0
  45. package/dist/chunk-4IS3QCOQ.cjs.map +1 -0
  46. package/dist/chunk-4NCDU5IG.cjs +56 -0
  47. package/dist/chunk-4NCDU5IG.cjs.map +1 -0
  48. package/dist/{chunk-E4IBHYJ7.cjs → chunk-6N6LIAUJ.cjs} +9 -9
  49. package/dist/{chunk-E4IBHYJ7.cjs.map → chunk-6N6LIAUJ.cjs.map} +1 -1
  50. package/dist/{chunk-3M7TAXNR.js → chunk-6ZPTZTKN.js} +3 -3
  51. package/dist/{chunk-3M7TAXNR.js.map → chunk-6ZPTZTKN.js.map} +1 -1
  52. package/dist/{chunk-MWVW4APN.cjs → chunk-7UTBDFFL.cjs} +4 -4
  53. package/dist/{chunk-MWVW4APN.cjs.map → chunk-7UTBDFFL.cjs.map} +1 -1
  54. package/dist/{chunk-FJ7YPVKV.js → chunk-7X6R3JIA.js} +3 -3
  55. package/dist/{chunk-FJ7YPVKV.js.map → chunk-7X6R3JIA.js.map} +1 -1
  56. package/dist/{chunk-GOALNQZ2.js → chunk-7YO7DNUV.js} +4 -83
  57. package/dist/chunk-7YO7DNUV.js.map +1 -0
  58. package/dist/{chunk-P2CA3XGI.js → chunk-7ZV67VZE.js} +4 -4
  59. package/dist/{chunk-P2CA3XGI.js.map → chunk-7ZV67VZE.js.map} +1 -1
  60. package/dist/chunk-ADW7ZYCY.cjs +2707 -0
  61. package/dist/chunk-ADW7ZYCY.cjs.map +1 -0
  62. package/dist/{chunk-2G75X6TS.cjs → chunk-AHHFFXJR.cjs} +3 -3
  63. package/dist/{chunk-2G75X6TS.cjs.map → chunk-AHHFFXJR.cjs.map} +1 -1
  64. package/dist/{chunk-VILW53UZ.js → chunk-BIQ7GSO2.js} +3 -3
  65. package/dist/{chunk-VILW53UZ.js.map → chunk-BIQ7GSO2.js.map} +1 -1
  66. package/dist/chunk-BM35CACB.js +148 -0
  67. package/dist/chunk-BM35CACB.js.map +1 -0
  68. package/dist/chunk-BNH4SXJB.js +874 -0
  69. package/dist/chunk-BNH4SXJB.js.map +1 -0
  70. package/dist/{chunk-XEAT7XJG.cjs → chunk-BUT6MF5K.cjs} +29 -13
  71. package/dist/chunk-BUT6MF5K.cjs.map +1 -0
  72. package/dist/{chunk-UAMXCMST.cjs → chunk-CFI3TQMA.cjs} +3 -3
  73. package/dist/{chunk-UAMXCMST.cjs.map → chunk-CFI3TQMA.cjs.map} +1 -1
  74. package/dist/{chunk-J5CSLNCN.cjs → chunk-COM7RNZU.cjs} +2 -2
  75. package/dist/{chunk-J5CSLNCN.cjs.map → chunk-COM7RNZU.cjs.map} +1 -1
  76. package/dist/{chunk-XI34EGK5.cjs → chunk-CPPUT74P.cjs} +9 -9
  77. package/dist/{chunk-XI34EGK5.cjs.map → chunk-CPPUT74P.cjs.map} +1 -1
  78. package/dist/{chunk-ACCAXVOG.js → chunk-CRS2CQWM.js} +134 -56
  79. package/dist/chunk-CRS2CQWM.js.map +1 -0
  80. package/dist/{chunk-OE5CKRUC.js → chunk-D22GE27K.js} +4 -4
  81. package/dist/{chunk-OE5CKRUC.js.map → chunk-D22GE27K.js.map} +1 -1
  82. package/dist/chunk-DXEPYK3I.cjs +92 -0
  83. package/dist/chunk-DXEPYK3I.cjs.map +1 -0
  84. package/dist/{chunk-ZGRCSNPK.js → chunk-E2PBPQGS.js} +4 -4
  85. package/dist/{chunk-ZGRCSNPK.js.map → chunk-E2PBPQGS.js.map} +1 -1
  86. package/dist/{chunk-5JJ2DAE4.js → chunk-ENMXHZNE.js} +3 -3
  87. package/dist/{chunk-5JJ2DAE4.js.map → chunk-ENMXHZNE.js.map} +1 -1
  88. package/dist/{chunk-XCP454Q6.js → chunk-F4N67NAF.js} +12 -3
  89. package/dist/chunk-F4N67NAF.js.map +1 -0
  90. package/dist/chunk-FBCDYTWM.js +385 -0
  91. package/dist/chunk-FBCDYTWM.js.map +1 -0
  92. package/dist/{chunk-VU6UTJRM.js → chunk-FIKO4WR6.js} +3 -3
  93. package/dist/{chunk-VU6UTJRM.js.map → chunk-FIKO4WR6.js.map} +1 -1
  94. package/dist/{chunk-DEDN5HAG.js → chunk-FZURBQJ2.js} +3 -3
  95. package/dist/{chunk-DEDN5HAG.js.map → chunk-FZURBQJ2.js.map} +1 -1
  96. package/dist/{chunk-JHULS3EC.js → chunk-GBUVIGD5.js} +89 -3
  97. package/dist/chunk-GBUVIGD5.js.map +1 -0
  98. package/dist/chunk-GU5OS7JJ.cjs +281 -0
  99. package/dist/chunk-GU5OS7JJ.cjs.map +1 -0
  100. package/dist/{chunk-V7D3YGUV.js → chunk-GVLNXPJX.js} +4 -4
  101. package/dist/{chunk-V7D3YGUV.js.map → chunk-GVLNXPJX.js.map} +1 -1
  102. package/dist/chunk-GVM6DTR5.js +90 -0
  103. package/dist/chunk-GVM6DTR5.js.map +1 -0
  104. package/dist/{chunk-SQHMGT4W.js → chunk-GW4RFJZ5.js} +7 -7
  105. package/dist/chunk-GW4RFJZ5.js.map +1 -0
  106. package/dist/{chunk-3QEVGSFG.cjs → chunk-GYXUS65N.cjs} +5 -5
  107. package/dist/{chunk-3QEVGSFG.cjs.map → chunk-GYXUS65N.cjs.map} +1 -1
  108. package/dist/{chunk-WGPLUCBD.js → chunk-H2IAMSHK.js} +3 -3
  109. package/dist/{chunk-WGPLUCBD.js.map → chunk-H2IAMSHK.js.map} +1 -1
  110. package/dist/{chunk-JID7AZTO.cjs → chunk-H3ROMJYI.cjs} +4 -4
  111. package/dist/{chunk-JID7AZTO.cjs.map → chunk-H3ROMJYI.cjs.map} +1 -1
  112. package/dist/{chunk-GD7EBGC4.cjs → chunk-HC3NAN55.cjs} +19 -19
  113. package/dist/{chunk-GD7EBGC4.cjs.map → chunk-HC3NAN55.cjs.map} +1 -1
  114. package/dist/{chunk-7ZXAQTV4.cjs → chunk-HIZWOAWY.cjs} +8 -8
  115. package/dist/{chunk-7ZXAQTV4.cjs.map → chunk-HIZWOAWY.cjs.map} +1 -1
  116. package/dist/{chunk-NV2CWBI2.cjs → chunk-IEY3ZJIT.cjs} +12 -3
  117. package/dist/chunk-IEY3ZJIT.cjs.map +1 -0
  118. package/dist/chunk-IT775BYG.js +179 -0
  119. package/dist/chunk-IT775BYG.js.map +1 -0
  120. package/dist/chunk-IYWG72DM.js +166 -0
  121. package/dist/chunk-IYWG72DM.js.map +1 -0
  122. package/dist/{chunk-2YCERQWC.js → chunk-JBIGSP2T.js} +6 -6
  123. package/dist/{chunk-2YCERQWC.js.map → chunk-JBIGSP2T.js.map} +1 -1
  124. package/dist/{chunk-IX6KFB3K.cjs → chunk-JELTRRR5.cjs} +9 -9
  125. package/dist/{chunk-IX6KFB3K.cjs.map → chunk-JELTRRR5.cjs.map} +1 -1
  126. package/dist/{chunk-YQDA366U.js → chunk-JHG3ELS2.js} +2 -2
  127. package/dist/{chunk-YQDA366U.js.map → chunk-JHG3ELS2.js.map} +1 -1
  128. package/dist/{chunk-WWJIW2IH.cjs → chunk-JSXIB6EJ.cjs} +4 -4
  129. package/dist/{chunk-WWJIW2IH.cjs.map → chunk-JSXIB6EJ.cjs.map} +1 -1
  130. package/dist/{chunk-WNM7IZJ7.js → chunk-K34DXMLZ.js} +7 -7
  131. package/dist/{chunk-WNM7IZJ7.js.map → chunk-K34DXMLZ.js.map} +1 -1
  132. package/dist/{chunk-FXO5ARBB.cjs → chunk-KDW6BD4O.cjs} +4 -4
  133. package/dist/{chunk-FXO5ARBB.cjs.map → chunk-KDW6BD4O.cjs.map} +1 -1
  134. package/dist/{chunk-Z5V7SAZ4.js → chunk-KFEN2SRZ.js} +3 -3
  135. package/dist/{chunk-Z5V7SAZ4.js.map → chunk-KFEN2SRZ.js.map} +1 -1
  136. package/dist/{chunk-2QKBTPUC.cjs → chunk-KGKBZN3T.cjs} +8 -8
  137. package/dist/{chunk-2QKBTPUC.cjs.map → chunk-KGKBZN3T.cjs.map} +1 -1
  138. package/dist/{chunk-UV2FVNWT.cjs → chunk-LFPJ3OUM.cjs} +5 -5
  139. package/dist/{chunk-UV2FVNWT.cjs.map → chunk-LFPJ3OUM.cjs.map} +1 -1
  140. package/dist/{chunk-WNAA6CLE.cjs → chunk-LHBWRMNC.cjs} +94 -2
  141. package/dist/chunk-LHBWRMNC.cjs.map +1 -0
  142. package/dist/{chunk-JI244Y7C.js → chunk-MLAWXPRY.js} +190 -5
  143. package/dist/chunk-MLAWXPRY.js.map +1 -0
  144. package/dist/chunk-N7C4OEP7.cjs +356 -0
  145. package/dist/chunk-N7C4OEP7.cjs.map +1 -0
  146. package/dist/{chunk-WNZAYBVB.cjs → chunk-NKV76R65.cjs} +48 -48
  147. package/dist/{chunk-WNZAYBVB.cjs.map → chunk-NKV76R65.cjs.map} +1 -1
  148. package/dist/{chunk-PYJDVWXM.js → chunk-NUB5HRKS.js} +3 -3
  149. package/dist/{chunk-PYJDVWXM.js.map → chunk-NUB5HRKS.js.map} +1 -1
  150. package/dist/{chunk-LL6IWKI3.js → chunk-OW3SQJ7P.js} +3 -3
  151. package/dist/{chunk-LL6IWKI3.js.map → chunk-OW3SQJ7P.js.map} +1 -1
  152. package/dist/{chunk-5GUOOLPR.cjs → chunk-P5CMZZRZ.cjs} +5 -5
  153. package/dist/{chunk-5GUOOLPR.cjs.map → chunk-P5CMZZRZ.cjs.map} +1 -1
  154. package/dist/{chunk-3T7QGLNB.js → chunk-PJEL5ZZV.js} +4 -2
  155. package/dist/chunk-PJEL5ZZV.js.map +1 -0
  156. package/dist/{chunk-H4ZXMQQW.js → chunk-QOVJ6Z6R.js} +3 -3
  157. package/dist/{chunk-H4ZXMQQW.js.map → chunk-QOVJ6Z6R.js.map} +1 -1
  158. package/dist/{chunk-U42F3HLE.cjs → chunk-QURJVPRH.cjs} +190 -5
  159. package/dist/chunk-QURJVPRH.cjs.map +1 -0
  160. package/dist/{chunk-X4XPNTCZ.cjs → chunk-R5Z7AOVU.cjs} +136 -58
  161. package/dist/chunk-R5Z7AOVU.cjs.map +1 -0
  162. package/dist/{chunk-TMMVIUUN.js → chunk-R6KPWIGO.js} +4 -4
  163. package/dist/{chunk-TMMVIUUN.js.map → chunk-R6KPWIGO.js.map} +1 -1
  164. package/dist/{chunk-22CYDCXA.js → chunk-RM2HPQIC.js} +105 -14
  165. package/dist/chunk-RM2HPQIC.js.map +1 -0
  166. package/dist/{chunk-ENKFJJZX.js → chunk-SD7ONW6S.js} +6 -6
  167. package/dist/{chunk-ENKFJJZX.js.map → chunk-SD7ONW6S.js.map} +1 -1
  168. package/dist/{chunk-RJ6NTJHC.js → chunk-SRMTRD7F.js} +3 -3
  169. package/dist/{chunk-RJ6NTJHC.js.map → chunk-SRMTRD7F.js.map} +1 -1
  170. package/dist/chunk-T4JYUICS.js +2657 -0
  171. package/dist/chunk-T4JYUICS.js.map +1 -0
  172. package/dist/{chunk-7ZDPD5ZX.cjs → chunk-T4L7Q5FA.cjs} +7 -7
  173. package/dist/{chunk-7ZDPD5ZX.cjs.map → chunk-T4L7Q5FA.cjs.map} +1 -1
  174. package/dist/{chunk-NJ6MY6V5.js → chunk-T5BBZQ66.js} +3 -3
  175. package/dist/{chunk-NJ6MY6V5.js.map → chunk-T5BBZQ66.js.map} +1 -1
  176. package/dist/{chunk-2IZLKPUW.js → chunk-THLIL6PY.js} +3 -3
  177. package/dist/{chunk-2IZLKPUW.js.map → chunk-THLIL6PY.js.map} +1 -1
  178. package/dist/{chunk-SGFYA22I.cjs → chunk-TJCX4OML.cjs} +8 -8
  179. package/dist/{chunk-SGFYA22I.cjs.map → chunk-TJCX4OML.cjs.map} +1 -1
  180. package/dist/{chunk-N6IY47YA.cjs → chunk-TTSSUOEV.cjs} +8 -8
  181. package/dist/{chunk-N6IY47YA.cjs.map → chunk-TTSSUOEV.cjs.map} +1 -1
  182. package/dist/{chunk-5MCBWTIF.cjs → chunk-TYE5K5WV.cjs} +4 -4
  183. package/dist/{chunk-5MCBWTIF.cjs.map → chunk-TYE5K5WV.cjs.map} +1 -1
  184. package/dist/{chunk-VOKVG3ER.js → chunk-UBSH27C2.js} +4 -4
  185. package/dist/{chunk-VOKVG3ER.js.map → chunk-UBSH27C2.js.map} +1 -1
  186. package/dist/{chunk-TAXD5ADA.cjs → chunk-UEDTZYGI.cjs} +3 -3
  187. package/dist/{chunk-TAXD5ADA.cjs.map → chunk-UEDTZYGI.cjs.map} +1 -1
  188. package/dist/{chunk-UQ3VVR6A.cjs → chunk-UPWIJC6I.cjs} +3 -3
  189. package/dist/{chunk-UQ3VVR6A.cjs.map → chunk-UPWIJC6I.cjs.map} +1 -1
  190. package/dist/{chunk-S7WCHDBO.js → chunk-VCI2Y7ST.js} +3 -3
  191. package/dist/{chunk-S7WCHDBO.js.map → chunk-VCI2Y7ST.js.map} +1 -1
  192. package/dist/chunk-VINZZQBD.cjs +323 -0
  193. package/dist/chunk-VINZZQBD.cjs.map +1 -0
  194. package/dist/{chunk-OD47TTAW.cjs → chunk-VOQJHSXN.cjs} +9 -9
  195. package/dist/{chunk-OD47TTAW.cjs.map → chunk-VOQJHSXN.cjs.map} +1 -1
  196. package/dist/chunk-VPTASZ2O.cjs +171 -0
  197. package/dist/chunk-VPTASZ2O.cjs.map +1 -0
  198. package/dist/chunk-WXFGHDTV.cjs +896 -0
  199. package/dist/chunk-WXFGHDTV.cjs.map +1 -0
  200. package/dist/{chunk-VNYW4C4J.cjs → chunk-X6A27RGO.cjs} +4 -84
  201. package/dist/chunk-X6A27RGO.cjs.map +1 -0
  202. package/dist/chunk-XBTKZCZF.js +333 -0
  203. package/dist/chunk-XBTKZCZF.js.map +1 -0
  204. package/dist/chunk-XDIMTPZU.cjs +202 -0
  205. package/dist/chunk-XDIMTPZU.cjs.map +1 -0
  206. package/dist/chunk-XDU65GLW.js +21 -0
  207. package/dist/chunk-XDU65GLW.js.map +1 -0
  208. package/dist/chunk-XI74P5F2.cjs +424 -0
  209. package/dist/chunk-XI74P5F2.cjs.map +1 -0
  210. package/dist/{chunk-WIAQQNFU.cjs → chunk-XRVMYT5G.cjs} +106 -13
  211. package/dist/chunk-XRVMYT5G.cjs.map +1 -0
  212. package/dist/chunk-XVW5DPPP.js +429 -0
  213. package/dist/chunk-XVW5DPPP.js.map +1 -0
  214. package/dist/chunk-Y4E2WRUR.cjs +188 -0
  215. package/dist/chunk-Y4E2WRUR.cjs.map +1 -0
  216. package/dist/chunk-Y4QNLW7W.js +300 -0
  217. package/dist/chunk-Y4QNLW7W.js.map +1 -0
  218. package/dist/{chunk-6EN3IQQI.cjs → chunk-YRHBSSQ3.cjs} +6 -6
  219. package/dist/{chunk-6EN3IQQI.cjs.map → chunk-YRHBSSQ3.cjs.map} +1 -1
  220. package/dist/{chunk-KZFBQ7GY.js → chunk-YU55JD35.js} +3 -3
  221. package/dist/{chunk-KZFBQ7GY.js.map → chunk-YU55JD35.js.map} +1 -1
  222. package/dist/chunk-YW2AKBLS.cjs +23 -0
  223. package/dist/chunk-YW2AKBLS.cjs.map +1 -0
  224. package/dist/{chunk-ELPW32ZI.cjs → chunk-ZTMYKAVU.cjs} +45 -45
  225. package/dist/{chunk-ELPW32ZI.cjs.map → chunk-ZTMYKAVU.cjs.map} +1 -1
  226. package/dist/{chunk-3QGS6CXD.js → chunk-ZYL4SNOR.js} +3 -3
  227. package/dist/{chunk-3QGS6CXD.js.map → chunk-ZYL4SNOR.js.map} +1 -1
  228. package/dist/components/Alert/index.d.cts +1 -1
  229. package/dist/components/Alert/index.d.ts +1 -1
  230. package/dist/components/AlertDialog/index.cjs +6 -5
  231. package/dist/components/AlertDialog/index.d.cts +28 -3
  232. package/dist/components/AlertDialog/index.d.ts +28 -3
  233. package/dist/components/AlertDialog/index.js +5 -4
  234. package/dist/components/AudioRecorder/index.d.cts +2 -2
  235. package/dist/components/AudioRecorder/index.d.ts +2 -2
  236. package/dist/components/Autocomplete/index.d.cts +8 -2
  237. package/dist/components/Autocomplete/index.d.ts +8 -2
  238. package/dist/components/Avatar/index.d.cts +1 -1
  239. package/dist/components/Avatar/index.d.ts +1 -1
  240. package/dist/components/Badge/index.d.cts +1 -1
  241. package/dist/components/Badge/index.d.ts +1 -1
  242. package/dist/components/BoardView/index.cjs +24 -0
  243. package/dist/components/BoardView/index.cjs.map +1 -0
  244. package/dist/components/BoardView/index.d.cts +41 -0
  245. package/dist/components/BoardView/index.d.ts +41 -0
  246. package/dist/components/BoardView/index.js +7 -0
  247. package/dist/components/BoardView/index.js.map +1 -0
  248. package/dist/components/Button/index.cjs +4 -3
  249. package/dist/components/Button/index.d.cts +2 -1
  250. package/dist/components/Button/index.d.ts +2 -1
  251. package/dist/components/Button/index.js +2 -1
  252. package/dist/components/CalendarView/index.cjs +23 -0
  253. package/dist/components/CalendarView/index.cjs.map +1 -0
  254. package/dist/components/CalendarView/index.d.cts +39 -0
  255. package/dist/components/CalendarView/index.d.ts +39 -0
  256. package/dist/components/CalendarView/index.js +10 -0
  257. package/dist/components/CalendarView/index.js.map +1 -0
  258. package/dist/components/Card/index.d.cts +3 -3
  259. package/dist/components/Card/index.d.ts +3 -3
  260. package/dist/components/Collapsible/index.cjs +6 -6
  261. package/dist/components/Collapsible/index.js +3 -3
  262. package/dist/components/CountryCodeDropdown/index.cjs +5 -5
  263. package/dist/components/CountryCodeDropdown/index.js +2 -2
  264. package/dist/components/CustomizableDashboard/index.cjs +10 -9
  265. package/dist/components/CustomizableDashboard/index.js +3 -2
  266. package/dist/components/Dropdown/index.cjs +10 -10
  267. package/dist/components/Dropdown/index.d.cts +2 -1
  268. package/dist/components/Dropdown/index.d.ts +2 -1
  269. package/dist/components/Dropdown/index.js +3 -3
  270. package/dist/components/FloatingWindow/index.cjs +5 -4
  271. package/dist/components/FloatingWindow/index.js +3 -2
  272. package/dist/components/GanttView/index.cjs +20 -0
  273. package/dist/components/GanttView/index.cjs.map +1 -0
  274. package/dist/components/GanttView/index.d.cts +36 -0
  275. package/dist/components/GanttView/index.d.ts +36 -0
  276. package/dist/components/GanttView/index.js +7 -0
  277. package/dist/components/GanttView/index.js.map +1 -0
  278. package/dist/components/GlossaryTooltip/index.cjs +3 -3
  279. package/dist/components/GlossaryTooltip/index.js +2 -2
  280. package/dist/components/KeyboardShortcutsOverlay/index.cjs +5 -5
  281. package/dist/components/KeyboardShortcutsOverlay/index.js +3 -3
  282. package/dist/components/ListView/index.cjs +23 -0
  283. package/dist/components/ListView/index.cjs.map +1 -0
  284. package/dist/components/ListView/index.d.cts +124 -0
  285. package/dist/components/ListView/index.d.ts +124 -0
  286. package/dist/components/ListView/index.js +10 -0
  287. package/dist/components/ListView/index.js.map +1 -0
  288. package/dist/components/Markdown/index.cjs +20 -19
  289. package/dist/components/Markdown/index.js +8 -7
  290. package/dist/components/MediaEditor/index.cjs +15 -14
  291. package/dist/components/MediaEditor/index.d.cts +91 -2
  292. package/dist/components/MediaEditor/index.d.ts +91 -2
  293. package/dist/components/MediaEditor/index.js +10 -9
  294. package/dist/components/MediaFeed/index.cjs +26 -0
  295. package/dist/components/MediaFeed/index.cjs.map +1 -0
  296. package/dist/components/MediaFeed/index.d.cts +104 -0
  297. package/dist/components/MediaFeed/index.d.ts +104 -0
  298. package/dist/components/MediaFeed/index.js +17 -0
  299. package/dist/components/MediaFeed/index.js.map +1 -0
  300. package/dist/components/MediaPlayer/index.cjs +7 -6
  301. package/dist/components/MediaPlayer/index.d.cts +19 -1
  302. package/dist/components/MediaPlayer/index.d.ts +19 -1
  303. package/dist/components/MediaPlayer/index.js +4 -3
  304. package/dist/components/MegaMenu/index.cjs +6 -5
  305. package/dist/components/MegaMenu/index.js +3 -2
  306. package/dist/components/Modal/index.cjs +10 -10
  307. package/dist/components/Modal/index.js +2 -2
  308. package/dist/components/Pagination/index.d.cts +1 -1
  309. package/dist/components/Pagination/index.d.ts +1 -1
  310. package/dist/components/PhoneInput/index.d.cts +36 -3
  311. package/dist/components/PhoneInput/index.d.ts +36 -3
  312. package/dist/components/Progress/index.d.cts +1 -1
  313. package/dist/components/Progress/index.d.ts +1 -1
  314. package/dist/components/Q/index.d.cts +2 -2
  315. package/dist/components/Q/index.d.ts +2 -2
  316. package/dist/components/QuickAction/index.d.cts +1 -1
  317. package/dist/components/QuickAction/index.d.ts +1 -1
  318. package/dist/components/RadialExplorer/index.cjs +5 -4
  319. package/dist/components/RadialExplorer/index.js +4 -3
  320. package/dist/components/RecordButton/index.d.cts +1 -1
  321. package/dist/components/RecordButton/index.d.ts +1 -1
  322. package/dist/components/RichTextEditor/index.cjs +9 -8
  323. package/dist/components/RichTextEditor/index.d.cts +7 -2
  324. package/dist/components/RichTextEditor/index.d.ts +7 -2
  325. package/dist/components/RichTextEditor/index.js +6 -5
  326. package/dist/components/ScrollArea/index.d.cts +1 -1
  327. package/dist/components/ScrollArea/index.d.ts +1 -1
  328. package/dist/components/SectionSpyNav/index.cjs +4 -3
  329. package/dist/components/SectionSpyNav/index.js +3 -2
  330. package/dist/components/Select/index.cjs +4 -4
  331. package/dist/components/Select/index.d.cts +1 -2
  332. package/dist/components/Select/index.d.ts +1 -2
  333. package/dist/components/Select/index.js +2 -2
  334. package/dist/components/Skeleton/index.d.cts +1 -1
  335. package/dist/components/Skeleton/index.d.ts +1 -1
  336. package/dist/components/Slider/index.d.cts +2 -2
  337. package/dist/components/Slider/index.d.ts +2 -2
  338. package/dist/components/SliderCalculator/index.cjs +4 -4
  339. package/dist/components/SliderCalculator/index.js +2 -2
  340. package/dist/components/SourceTip/index.cjs +3 -3
  341. package/dist/components/SourceTip/index.js +2 -2
  342. package/dist/components/Spinner/index.d.cts +2 -2
  343. package/dist/components/Spinner/index.d.ts +2 -2
  344. package/dist/components/SuperChat/index.cjs +1378 -819
  345. package/dist/components/SuperChat/index.cjs.map +1 -1
  346. package/dist/components/SuperChat/index.d.cts +35 -8
  347. package/dist/components/SuperChat/index.d.ts +35 -8
  348. package/dist/components/SuperChat/index.js +1370 -811
  349. package/dist/components/SuperChat/index.js.map +1 -1
  350. package/dist/components/SuperChat/plugins/index.cjs +6 -6
  351. package/dist/components/SuperChat/plugins/index.d.cts +2 -3
  352. package/dist/components/SuperChat/plugins/index.d.ts +2 -3
  353. package/dist/components/SuperChat/plugins/index.js +5 -5
  354. package/dist/components/Text/index.d.cts +3 -3
  355. package/dist/components/Text/index.d.ts +3 -3
  356. package/dist/components/Textarea/index.d.cts +1 -2
  357. package/dist/components/Textarea/index.d.ts +1 -2
  358. package/dist/components/ThemeProvider/index.cjs +9 -9
  359. package/dist/components/ThemeProvider/index.d.cts +3 -1
  360. package/dist/components/ThemeProvider/index.d.ts +3 -1
  361. package/dist/components/ThemeProvider/index.js +3 -3
  362. package/dist/components/Tooltip/index.cjs +3 -3
  363. package/dist/components/Tooltip/index.js +2 -2
  364. package/dist/components/TranscriptView/index.d.cts +85 -4
  365. package/dist/components/TranscriptView/index.d.ts +85 -4
  366. package/dist/components/ViewSet/index.cjs +24 -0
  367. package/dist/components/ViewSet/index.cjs.map +1 -0
  368. package/dist/components/ViewSet/index.d.cts +200 -0
  369. package/dist/components/ViewSet/index.d.ts +200 -0
  370. package/dist/components/ViewSet/index.js +15 -0
  371. package/dist/components/ViewSet/index.js.map +1 -0
  372. package/dist/components/ViewSwitcher/index.cjs +20 -0
  373. package/dist/components/ViewSwitcher/index.cjs.map +1 -0
  374. package/dist/components/ViewSwitcher/index.d.cts +4 -0
  375. package/dist/components/ViewSwitcher/index.d.ts +4 -0
  376. package/dist/components/ViewSwitcher/index.js +7 -0
  377. package/dist/components/ViewSwitcher/index.js.map +1 -0
  378. package/dist/datavis.cjs +3 -2
  379. package/dist/datavis.cjs.map +1 -1
  380. package/dist/datavis.d.cts +167 -13
  381. package/dist/datavis.d.ts +167 -13
  382. package/dist/datavis.js +2 -1
  383. package/dist/datavis.js.map +1 -1
  384. package/dist/deck.cjs +3360 -0
  385. package/dist/deck.cjs.map +1 -0
  386. package/dist/deck.d.cts +712 -0
  387. package/dist/deck.d.ts +712 -0
  388. package/dist/deck.js +3316 -0
  389. package/dist/deck.js.map +1 -0
  390. package/dist/esheet.cjs +14 -13
  391. package/dist/esheet.cjs.map +1 -1
  392. package/dist/esheet.d.cts +183 -1
  393. package/dist/esheet.d.ts +183 -1
  394. package/dist/esheet.js +11 -10
  395. package/dist/esheet.js.map +1 -1
  396. package/dist/globe.cjs +2 -2
  397. package/dist/globe.js +1 -1
  398. package/dist/hooks/index.cjs +60 -27
  399. package/dist/hooks/index.d.cts +590 -31
  400. package/dist/hooks/index.d.ts +590 -31
  401. package/dist/hooks/index.js +6 -5
  402. package/dist/icons-wBacj6BW.d.cts +142 -0
  403. package/dist/icons-wBacj6BW.d.ts +142 -0
  404. package/dist/index-DoYYWsNc.d.cts +127 -0
  405. package/dist/index-DoYYWsNc.d.ts +127 -0
  406. package/dist/index.cjs +1420 -1048
  407. package/dist/index.cjs.map +1 -1
  408. package/dist/index.d.cts +8796 -482
  409. package/dist/index.d.ts +8796 -482
  410. package/dist/index.js +368 -232
  411. package/dist/index.js.map +1 -1
  412. package/dist/kerebron.cjs +58 -19
  413. package/dist/kerebron.cjs.map +1 -1
  414. package/dist/kerebron.css +115 -0
  415. package/dist/kerebron.d.cts +37 -0
  416. package/dist/kerebron.d.ts +37 -0
  417. package/dist/kerebron.js +58 -19
  418. package/dist/kerebron.js.map +1 -1
  419. package/dist/maps.cjs +160 -0
  420. package/dist/maps.cjs.map +1 -0
  421. package/dist/maps.d.cts +42 -0
  422. package/dist/maps.d.ts +42 -0
  423. package/dist/maps.js +138 -0
  424. package/dist/maps.js.map +1 -0
  425. package/dist/motion.cjs +7 -7
  426. package/dist/motion.d.cts +186 -2
  427. package/dist/motion.d.ts +186 -2
  428. package/dist/motion.js +2 -2
  429. package/dist/q.d.cts +25 -3
  430. package/dist/q.d.ts +25 -3
  431. package/dist/styles/effects.css +133 -0
  432. package/dist/styles/init.css +3 -0
  433. package/dist/styles.css +1 -1
  434. package/dist/tailwind-preset.cjs +4 -4
  435. package/dist/tailwind-preset.js +1 -1
  436. package/dist/templates.cjs +156 -0
  437. package/dist/templates.cjs.map +1 -0
  438. package/dist/templates.d.cts +734 -0
  439. package/dist/templates.d.ts +734 -0
  440. package/dist/templates.js +11 -0
  441. package/dist/templates.js.map +1 -0
  442. package/dist/types-Cx1FHLq2.d.cts +548 -0
  443. package/dist/types-Cx1FHLq2.d.ts +548 -0
  444. package/dist/types-DsdZvEI1.d.cts +92 -0
  445. package/dist/types-DsdZvEI1.d.ts +92 -0
  446. package/dist/utils/index.d.cts +13 -2
  447. package/dist/utils/index.d.ts +13 -2
  448. package/package.json +62 -13
  449. package/dist/Animated-XmH6k8pZ.d.cts +0 -188
  450. package/dist/Animated-XmH6k8pZ.d.ts +0 -188
  451. package/dist/CsvBlock-ROJCKJDP.cjs +0 -16
  452. package/dist/CsvBlock-UWPMTLE2.js +0 -7
  453. package/dist/HtmlPreviewBlock-DWFN6EUB.cjs +0 -16
  454. package/dist/HtmlPreviewBlock-ME5U3XNS.js +0 -7
  455. package/dist/MedicationEditor-Bp4NLy7y.d.cts +0 -352
  456. package/dist/MedicationEditor-Bp4NLy7y.d.ts +0 -352
  457. package/dist/MermaidBlock-2B6CPD6Y.js +0 -7
  458. package/dist/MermaidBlock-D2UC5M55.cjs +0 -16
  459. package/dist/SurveyBlock-4CD4AYMJ.cjs +0 -16
  460. package/dist/SurveyBlock-4DO62RBT.js +0 -7
  461. package/dist/chunk-22CYDCXA.js.map +0 -1
  462. package/dist/chunk-3T7QGLNB.js.map +0 -1
  463. package/dist/chunk-6HFFWEM3.cjs +0 -22
  464. package/dist/chunk-6HFFWEM3.cjs.map +0 -1
  465. package/dist/chunk-ACCAXVOG.js.map +0 -1
  466. package/dist/chunk-GOALNQZ2.js.map +0 -1
  467. package/dist/chunk-HB7C7NB5.js +0 -20
  468. package/dist/chunk-HB7C7NB5.js.map +0 -1
  469. package/dist/chunk-JHULS3EC.js.map +0 -1
  470. package/dist/chunk-JI244Y7C.js.map +0 -1
  471. package/dist/chunk-JYZW2PZS.cjs.map +0 -1
  472. package/dist/chunk-NV2CWBI2.cjs.map +0 -1
  473. package/dist/chunk-SQHMGT4W.js.map +0 -1
  474. package/dist/chunk-U42F3HLE.cjs.map +0 -1
  475. package/dist/chunk-VKELAMAZ.js.map +0 -1
  476. package/dist/chunk-VNYW4C4J.cjs.map +0 -1
  477. package/dist/chunk-WIAQQNFU.cjs.map +0 -1
  478. package/dist/chunk-WNAA6CLE.cjs.map +0 -1
  479. package/dist/chunk-WNJRS7Y7.cjs.map +0 -1
  480. package/dist/chunk-X4XPNTCZ.cjs.map +0 -1
  481. package/dist/chunk-XCP454Q6.js.map +0 -1
  482. package/dist/chunk-XEAT7XJG.cjs.map +0 -1
  483. package/dist/html-MdxqSzjD.d.cts +0 -13
  484. package/dist/html-MdxqSzjD.d.ts +0 -13
  485. package/dist/orderRows-BUJYgSc7.d.cts +0 -221
  486. package/dist/orderRows-BUJYgSc7.d.ts +0 -221
  487. package/dist/transcript-Cg7uSW-C.d.cts +0 -84
  488. package/dist/transcript-Cg7uSW-C.d.ts +0 -84
  489. package/dist/types-B97JNRNQ.d.cts +0 -251
  490. package/dist/types-CnPEwzlp.d.cts +0 -254
  491. package/dist/types-CnPEwzlp.d.ts +0 -254
  492. package/dist/types-gZXrfLj6.d.ts +0 -251
  493. package/dist/useAnchoredPosition-CKwLSQW8.d.cts +0 -76
  494. package/dist/useAnchoredPosition-CKwLSQW8.d.ts +0 -76
  495. package/dist/useTheme-B9SWu6ui.d.cts +0 -24
  496. package/dist/useTheme-B9SWu6ui.d.ts +0 -24
  497. package/dist/useTranscriptEdits-CGzlemHT.d.cts +0 -182
  498. package/dist/useTranscriptEdits-D32bLs0l.d.ts +0 -182
@@ -1,418 +1,235 @@
1
1
  import { TextRenderContext } from '../../chunk-I6CY5C6A.js';
2
2
  export { TextRenderContext, useTextRenderContext } from '../../chunk-I6CY5C6A.js';
3
- import { ChatBubble, MCPToolCallDisplay, AITypingIndicator, SparklesIcon, CloseIcon } from '../../chunk-22CYDCXA.js';
4
- import { notifyComposerMigrationOnce, ChatComposer } from '../../chunk-ACCAXVOG.js';
5
- import { Dropdown, DropdownSubmenu, DropdownItem } from '../../chunk-ZGRCSNPK.js';
3
+ import { ChatBubble, MCPToolCallDisplay, AITypingIndicator, SparklesIcon, ButtonGroup, CloseIcon, JumpToBottomButton } from '../../chunk-RM2HPQIC.js';
4
+ import { notifyComposerMigrationOnce, ChatComposer } from '../../chunk-CRS2CQWM.js';
5
+ import { MediaFeed } from '../../chunk-BNH4SXJB.js';
6
+ import '../../chunk-RISZWWEQ.js';
7
+ import { MediaPlayer } from '../../chunk-2JICT4A2.js';
8
+ import { Dropdown, DropdownSubmenu, DropdownItem } from '../../chunk-E2PBPQGS.js';
9
+ import '../../chunk-VVDE4CHU.js';
6
10
  import { Avatar } from '../../chunk-HZ4MBUC3.js';
7
11
  import '../../chunk-IQ4KQJAO.js';
8
- import '../../chunk-VVDE4CHU.js';
12
+ import { useStickToBottom, useStreamEndedBelowFold } from '../../chunk-BM35CACB.js';
13
+ import '../../chunk-GW4RFJZ5.js';
14
+ import '../../chunk-ENMXHZNE.js';
9
15
  import '../../chunk-6NZXWKUE.js';
10
16
  import '../../chunk-3IMM2PM4.js';
17
+ import '../../chunk-4SMSH4OY.js';
18
+ import '../../chunk-T4ME7QCT.js';
11
19
  import '../../chunk-62ZOA6PX.js';
12
20
  import '../../chunk-WSNMQQ4P.js';
13
- import '../../chunk-T4ME7QCT.js';
21
+ import '../../chunk-VSQF22GL.js';
14
22
  import '../../chunk-BKSPDTX4.js';
23
+ import { usePrefersReducedMotion } from '../../chunk-XDU65GLW.js';
24
+ import { Button } from '../../chunk-7YO7DNUV.js';
15
25
  import { Badge } from '../../chunk-BMSG4NBH.js';
16
- import '../../chunk-XCP454Q6.js';
26
+ import '../../chunk-GVM6DTR5.js';
27
+ import { AnimatedPresence, Animated } from '../../chunk-F4N67NAF.js';
17
28
  import { cn } from '../../chunk-TQONQSJO.js';
18
29
  import '../../chunk-PX6F3LHL.js';
19
- import * as React2 from 'react';
30
+ import * as React3 from 'react';
31
+ import { createElement } from 'react';
32
+ import { Ellipsis, Check, Clipboard, Pencil, Play, ArrowLeft } from 'lucide-react';
33
+ import { cva } from 'class-variance-authority';
34
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
20
35
  import Markdown, { defaultUrlTransform } from 'react-markdown';
21
36
  import remarkGfm from 'remark-gfm';
22
37
  import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
23
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
24
- import { cva } from 'class-variance-authority';
25
- import { Ellipsis, Check, Clipboard, Pencil } from 'lucide-react';
26
38
  import { useVirtualizer } from '@tanstack/react-virtual';
27
39
 
28
- function remarkPreserveLineBreaks() {
29
- const splitNode = (node) => {
30
- if (!node.children) return;
31
- const next = [];
32
- for (const child of node.children) {
33
- if (child.type === "text" && child.value && child.value.includes("\n")) {
34
- const segments = child.value.split("\n");
35
- segments.forEach((segment, i) => {
36
- if (i > 0) next.push({ type: "break" });
37
- if (segment) next.push({ type: "text", value: segment });
38
- });
39
- } else {
40
- splitNode(child);
41
- next.push(child);
42
- }
40
+ function MessageMedia({
41
+ attachment,
42
+ onOpen,
43
+ openLabel,
44
+ playLabel,
45
+ errorLabel,
46
+ retryLabel,
47
+ launchId
48
+ }) {
49
+ const playable = attachment.kind !== "image";
50
+ const actionLabel = playable ? playLabel : openLabel;
51
+ return /* @__PURE__ */ jsxs(
52
+ "div",
53
+ {
54
+ "data-slot": "superchat-message-media",
55
+ className: "mt-3 flex w-72 max-w-full flex-col gap-2",
56
+ children: [
57
+ attachment.title && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: attachment.title }),
58
+ attachment.kind === "image" && attachment.src ? /* @__PURE__ */ jsx(
59
+ "img",
60
+ {
61
+ src: attachment.src,
62
+ alt: attachment.alt ?? attachment.title ?? "",
63
+ loading: "lazy",
64
+ className: "max-h-72 w-full rounded-lg object-contain"
65
+ }
66
+ ) : (attachment.kind === "video" || attachment.kind === "audio") && attachment.src ? (
67
+ // An opaque themed surface: the player's semi-transparent states
68
+ // (error, loading) must never compose onto a colored chat bubble.
69
+ /* @__PURE__ */ jsx("div", { className: "bg-background overflow-hidden rounded-lg", children: /* @__PURE__ */ jsx(
70
+ MediaPlayer,
71
+ {
72
+ src: attachment.src,
73
+ kind: attachment.kind,
74
+ poster: attachment.poster,
75
+ "aria-label": attachment.alt ?? attachment.title ?? openLabel,
76
+ controls: !onOpen,
77
+ preload: "metadata",
78
+ labels: { error: errorLabel, retry: retryLabel },
79
+ className: "max-h-72"
80
+ }
81
+ ) })
82
+ ) : attachment.poster ? /* @__PURE__ */ jsx(
83
+ "img",
84
+ {
85
+ src: attachment.poster,
86
+ alt: attachment.alt ?? attachment.title ?? "",
87
+ loading: "lazy",
88
+ className: "max-h-72 w-full rounded-lg object-contain"
89
+ }
90
+ ) : null,
91
+ attachment.caption && /* @__PURE__ */ jsx("p", { className: "text-sm", children: attachment.caption }),
92
+ onOpen && /* @__PURE__ */ jsx(ButtonGroup, { children: /* @__PURE__ */ jsx(
93
+ Button,
94
+ {
95
+ "data-media-launch-id": launchId,
96
+ variant: "secondary",
97
+ size: "sm",
98
+ leftIcon: playable ? /* @__PURE__ */ jsx(Play, { className: "size-4", "aria-hidden": "true" }) : void 0,
99
+ "aria-label": playable && attachment.title ? `${playLabel} ${attachment.title}` : actionLabel,
100
+ onClick: () => onOpen(playable),
101
+ children: actionLabel
102
+ }
103
+ ) })
104
+ ]
43
105
  }
44
- node.children = next;
45
- };
46
- return (tree) => splitNode(tree);
106
+ );
47
107
  }
48
- function baseSanitizeSchema() {
49
- const schema = JSON.parse(JSON.stringify(defaultSchema));
50
- const attributes = schema.attributes ?? {};
51
- const allowClass = (tag) => {
52
- const existing = attributes[tag] ?? [];
53
- const withoutClass = existing.filter(
54
- (a) => !(Array.isArray(a) && a[0] === "className")
55
- );
56
- attributes[tag] = [...withoutClass, "className"];
57
- };
58
- allowClass("code");
59
- allowClass("pre");
60
- allowClass("span");
61
- allowClass("div");
62
- schema.attributes = attributes;
63
- return schema;
108
+ function formatTime(time) {
109
+ return new Date(time).toLocaleTimeString(void 0, {
110
+ hour: "numeric",
111
+ minute: "2-digit"
112
+ });
64
113
  }
65
- function mergeSanitizeSchema(base, extra) {
66
- if (!extra) return base;
67
- const out = { ...base };
68
- if (Array.isArray(extra.tagNames)) {
69
- const a = base.tagNames ?? [];
70
- out.tagNames = Array.from(/* @__PURE__ */ new Set([...a, ...extra.tagNames]));
114
+ function byTime(a, b) {
115
+ return new Date(a.time).getTime() - new Date(b.time).getTime();
116
+ }
117
+ function lastActivityOf(c) {
118
+ if (c.lastActivity) return new Date(c.lastActivity).getTime();
119
+ const last = lastMessageByTime(c.thread);
120
+ return last ? new Date(last.time).getTime() : 0;
121
+ }
122
+ function escapeRegExp(value) {
123
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
124
+ }
125
+ function detectMentions(text, participants) {
126
+ const ids = [];
127
+ for (const p of participants) {
128
+ if (p.kind === "system") continue;
129
+ const token = "@" + p.name.split(" ")[0];
130
+ const pattern = new RegExp(
131
+ `(?<![\\w@])${escapeRegExp(token)}(?![\\w])`,
132
+ "i"
133
+ );
134
+ if (pattern.test(text)) ids.push(p.id);
71
135
  }
72
- if (extra.attributes && typeof extra.attributes === "object") {
73
- const baseAttrs = {
74
- ...base.attributes ?? {}
75
- };
76
- for (const [tag, attrs] of Object.entries(
77
- extra.attributes
78
- )) {
79
- baseAttrs[tag] = [...baseAttrs[tag] ?? [], ...attrs];
136
+ return ids;
137
+ }
138
+ function lastMessageByTime(thread) {
139
+ let latest;
140
+ let latestTime = -Infinity;
141
+ for (const message of thread) {
142
+ const t = new Date(message.time).getTime();
143
+ if (t >= latestTime) {
144
+ latest = message;
145
+ latestTime = t;
80
146
  }
81
- out.attributes = baseAttrs;
82
147
  }
83
- if (extra.protocols && typeof extra.protocols === "object") {
84
- const baseProtocols = {
85
- ...base.protocols ?? {}
86
- };
87
- for (const [attr, protocols] of Object.entries(
88
- extra.protocols
89
- )) {
90
- baseProtocols[attr] = Array.from(
91
- /* @__PURE__ */ new Set([...baseProtocols[attr] ?? [], ...protocols])
92
- );
148
+ return latest;
149
+ }
150
+ function parseHexColor(value) {
151
+ const hex = value.trim();
152
+ if (!/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(hex)) return null;
153
+ const normalized = hex.length === 4 ? "#" + [...hex.slice(1)].map((char) => char + char).join("") : hex;
154
+ return [1, 3, 5].map(
155
+ (start) => parseInt(normalized.slice(start, start + 2), 16)
156
+ );
157
+ }
158
+ function relativeLuminanceChannel(channel) {
159
+ const normalized = channel / 255;
160
+ return normalized <= 0.03928 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4;
161
+ }
162
+ function relativeLuminance(value) {
163
+ const rgb = parseHexColor(value);
164
+ if (!rgb) return null;
165
+ const [red, green, blue] = rgb;
166
+ return 0.2126 * relativeLuminanceChannel(red) + 0.7152 * relativeLuminanceChannel(green) + 0.0722 * relativeLuminanceChannel(blue);
167
+ }
168
+ function contrastRatio(foreground, background) {
169
+ const foregroundLuminance = relativeLuminance(foreground);
170
+ const backgroundLuminance = relativeLuminance(background);
171
+ if (foregroundLuminance === null || backgroundLuminance === null) return null;
172
+ const lighter = Math.max(foregroundLuminance, backgroundLuminance);
173
+ const darker = Math.min(foregroundLuminance, backgroundLuminance);
174
+ return (lighter + 0.05) / (darker + 0.05);
175
+ }
176
+ function minimumContrastRatio(value, backgrounds) {
177
+ const contrasts = backgrounds.map((background) => contrastRatio(value, background)).filter((contrast) => contrast !== null);
178
+ if (contrasts.length !== backgrounds.length) return null;
179
+ return Math.min(...contrasts);
180
+ }
181
+ function accessibleAccentTextColor(value) {
182
+ if (!value) return void 0;
183
+ const contrast = minimumContrastRatio(value, ["#f5f5f5", "#262626"]);
184
+ if (contrast === null) return value;
185
+ return contrast < 4.5 ? void 0 : value;
186
+ }
187
+ function ParticipantAvatar({
188
+ participant
189
+ }) {
190
+ const isAgent = participant?.kind === "agent";
191
+ const backgroundColor = participant?.color ?? (isAgent ? "var(--mieweb-primary-700, #1f2937)" : "#64748b");
192
+ return /* @__PURE__ */ jsx(
193
+ Avatar,
194
+ {
195
+ size: "xs",
196
+ src: participant?.avatar,
197
+ alt: "",
198
+ name: participant?.name ?? "?",
199
+ fallback: isAgent ? /* @__PURE__ */ jsx(SparklesIcon, { size: "sm" }) : void 0,
200
+ style: { backgroundColor },
201
+ "aria-hidden": "true",
202
+ className: "shrink-0"
93
203
  }
94
- out.protocols = baseProtocols;
95
- }
96
- for (const [k, v] of Object.entries(extra)) {
97
- if (k === "tagNames" || k === "attributes" || k === "protocols") continue;
98
- out[k] = v;
99
- }
100
- return out;
204
+ );
101
205
  }
102
- function baseComponents() {
103
- return {
104
- a: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
105
- "a",
206
+ function ReferenceChip({
207
+ reference,
208
+ linkBuilder,
209
+ onReferenceClick
210
+ }) {
211
+ const href = linkBuilder?.(reference);
212
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
213
+ /* @__PURE__ */ jsx(
214
+ Badge,
106
215
  {
107
- ...props,
108
- className: cn(
109
- "text-primary-800 hover:text-primary-900 dark:text-primary-300 underline underline-offset-2",
110
- props.className
111
- ),
112
- target: props.target ?? "_blank",
113
- rel: props.rel ?? "noopener noreferrer",
114
- children
216
+ variant: "default",
217
+ size: "sm",
218
+ className: "rounded px-1.5 text-[10px] font-semibold tracking-wide uppercase",
219
+ children: reference.refType
115
220
  }
116
221
  ),
117
- pre: ({ node: _node, ...props }) => /* @__PURE__ */ jsx(
118
- "pre",
222
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: reference.title })
223
+ ] });
224
+ const className = "inline-flex max-w-full items-center gap-2 rounded-lg border border-neutral-200 bg-white px-3 py-1.5 text-sm text-neutral-700 hover:border-primary-300 dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-200";
225
+ if (href) {
226
+ return /* @__PURE__ */ jsx(
227
+ "a",
119
228
  {
120
- ...props,
121
- tabIndex: 0,
122
- className: cn(
123
- "overflow-x-auto rounded-lg bg-neutral-900 p-3 text-sm text-neutral-100 dark:bg-neutral-950",
124
- props.className
125
- )
126
- }
127
- ),
128
- code: ({ node: _node, ...props }) => {
129
- const isBlock = typeof props.className === "string" && props.className.includes("language-");
130
- return /* @__PURE__ */ jsx(
131
- "code",
132
- {
133
- ...props,
134
- className: cn(
135
- !isBlock && "rounded bg-neutral-200 px-1 py-0.5 text-[0.85em] text-neutral-800 dark:bg-neutral-700 dark:text-neutral-100",
136
- props.className
137
- )
138
- }
139
- );
140
- },
141
- input: ({ node: _node, ...props }) => {
142
- if (props.type === "checkbox") {
143
- return /* @__PURE__ */ jsx(
144
- "input",
145
- {
146
- ...props,
147
- "aria-label": props["aria-label"] ?? (props["aria-labelledby"] ? void 0 : "Task list item")
148
- }
149
- );
150
- }
151
- return /* @__PURE__ */ jsx("input", { ...props });
152
- },
153
- table: ({ node: _node, ...props }) => /* @__PURE__ */ jsx("div", { className: "my-2 overflow-x-auto", children: /* @__PURE__ */ jsx(
154
- "table",
155
- {
156
- ...props,
157
- className: cn(
158
- "w-full border-collapse text-sm [&_td]:border [&_td]:border-neutral-200 [&_td]:px-2 [&_td]:py-1 dark:[&_td]:border-neutral-700 [&_th]:border [&_th]:border-neutral-200 [&_th]:px-2 [&_th]:py-1 [&_th]:text-start dark:[&_th]:border-neutral-700",
159
- props.className
160
- )
161
- }
162
- ) }),
163
- // Tailwind's preflight resets list markers/padding; restore them explicitly
164
- // so bullets/numbers show without depending on the typography plugin.
165
- ul: ({ node: _node, ...props }) => /* @__PURE__ */ jsx("ul", { ...props, className: cn("list-disc ps-5", props.className) }),
166
- ol: ({ node: _node, ...props }) => /* @__PURE__ */ jsx("ol", { ...props, className: cn("list-decimal ps-5", props.className) }),
167
- li: ({ node: _node, ...props }) => /* @__PURE__ */ jsx("li", { ...props, className: cn("ps-1", props.className) }),
168
- // Preflight also flattens headings to body size/weight; restore a sensible
169
- // hierarchy without depending on the typography plugin.
170
- h1: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
171
- "h1",
172
- {
173
- ...props,
174
- className: cn("mt-3 mb-1 text-xl font-semibold", props.className),
175
- children
176
- }
177
- ),
178
- h2: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
179
- "h2",
180
- {
181
- ...props,
182
- className: cn("mt-3 mb-1 text-lg font-semibold", props.className),
183
- children
184
- }
185
- ),
186
- h3: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
187
- "h3",
188
- {
189
- ...props,
190
- className: cn("mt-2 mb-1 text-base font-semibold", props.className),
191
- children
192
- }
193
- ),
194
- h4: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
195
- "h4",
196
- {
197
- ...props,
198
- className: cn("mt-2 mb-1 text-sm font-semibold", props.className),
199
- children
200
- }
201
- ),
202
- h5: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
203
- "h5",
204
- {
205
- ...props,
206
- className: cn("mt-2 mb-1 text-sm font-semibold", props.className),
207
- children
208
- }
209
- ),
210
- h6: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
211
- "h6",
212
- {
213
- ...props,
214
- className: cn(
215
- "mt-2 mb-1 text-xs font-semibold tracking-wide uppercase",
216
- props.className
217
- ),
218
- children
219
- }
220
- ),
221
- hr: ({ node: _node, ...props }) => /* @__PURE__ */ jsx(
222
- "hr",
223
- {
224
- ...props,
225
- className: cn(
226
- "my-2 border-neutral-300 dark:border-neutral-600",
227
- props.className
228
- )
229
- }
230
- )
231
- };
232
- }
233
- function createMarkdownRenderer(options = {}) {
234
- const { plugins = [], trusted = false } = options;
235
- const remarkPlugins = [
236
- remarkGfm,
237
- remarkPreserveLineBreaks,
238
- ...plugins.flatMap((p) => p.remarkPlugins ?? [])
239
- ];
240
- const pluginRehype = plugins.flatMap(
241
- (p) => p.rehypePlugins ?? []
242
- );
243
- const sanitizeSchema = plugins.reduce(
244
- (acc, p) => mergeSanitizeSchema(acc, p.sanitizeSchema),
245
- baseSanitizeSchema()
246
- );
247
- const rehypePlugins = trusted ? pluginRehype : [...pluginRehype, [rehypeSanitize, sanitizeSchema]];
248
- const components = plugins.reduce(
249
- (acc, p) => ({ ...acc, ...p.components }),
250
- baseComponents()
251
- );
252
- const MarkdownRenderer = (text, ctx) => /* @__PURE__ */ jsx(
253
- MarkdownContent,
254
- {
255
- text,
256
- messageId: ctx.messageId,
257
- streaming: ctx.streaming,
258
- remarkPlugins,
259
- rehypePlugins,
260
- components
261
- },
262
- ctx.messageId
263
- );
264
- return MarkdownRenderer;
265
- }
266
- var transformUrl = (url, key, node) => {
267
- if (key === "src" && node.tagName === "img" && (/^data:image\//i.test(url) || /^blob:/i.test(url))) {
268
- return url;
269
- }
270
- return defaultUrlTransform(url);
271
- };
272
- var MarkdownContent = React2.memo(function MarkdownContent2({
273
- text,
274
- messageId,
275
- streaming,
276
- remarkPlugins,
277
- rehypePlugins,
278
- components
279
- }) {
280
- return /* @__PURE__ */ jsx(TextRenderContext.Provider, { value: { messageId, streaming }, children: /* @__PURE__ */ jsx(
281
- Markdown,
282
- {
283
- remarkPlugins,
284
- rehypePlugins,
285
- urlTransform: transformUrl,
286
- components,
287
- children: text
288
- }
289
- ) });
290
- });
291
- function formatTime(time) {
292
- return new Date(time).toLocaleTimeString(void 0, {
293
- hour: "numeric",
294
- minute: "2-digit"
295
- });
296
- }
297
- function byTime(a, b) {
298
- return new Date(a.time).getTime() - new Date(b.time).getTime();
299
- }
300
- function lastActivityOf(c) {
301
- if (c.lastActivity) return new Date(c.lastActivity).getTime();
302
- const last = lastMessageByTime(c.thread);
303
- return last ? new Date(last.time).getTime() : 0;
304
- }
305
- function escapeRegExp(value) {
306
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
307
- }
308
- function detectMentions(text, participants) {
309
- const ids = [];
310
- for (const p of participants) {
311
- if (p.kind === "system") continue;
312
- const token = "@" + p.name.split(" ")[0];
313
- const pattern = new RegExp(
314
- `(?<![\\w@])${escapeRegExp(token)}(?![\\w])`,
315
- "i"
316
- );
317
- if (pattern.test(text)) ids.push(p.id);
318
- }
319
- return ids;
320
- }
321
- function lastMessageByTime(thread) {
322
- let latest;
323
- let latestTime = -Infinity;
324
- for (const message of thread) {
325
- const t = new Date(message.time).getTime();
326
- if (t >= latestTime) {
327
- latest = message;
328
- latestTime = t;
329
- }
330
- }
331
- return latest;
332
- }
333
- function parseHexColor(value) {
334
- const hex = value.trim();
335
- if (!/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(hex)) return null;
336
- const normalized = hex.length === 4 ? "#" + [...hex.slice(1)].map((char) => char + char).join("") : hex;
337
- return [1, 3, 5].map(
338
- (start) => parseInt(normalized.slice(start, start + 2), 16)
339
- );
340
- }
341
- function relativeLuminanceChannel(channel) {
342
- const normalized = channel / 255;
343
- return normalized <= 0.03928 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4;
344
- }
345
- function relativeLuminance(value) {
346
- const rgb = parseHexColor(value);
347
- if (!rgb) return null;
348
- const [red, green, blue] = rgb;
349
- return 0.2126 * relativeLuminanceChannel(red) + 0.7152 * relativeLuminanceChannel(green) + 0.0722 * relativeLuminanceChannel(blue);
350
- }
351
- function contrastRatio(foreground, background) {
352
- const foregroundLuminance = relativeLuminance(foreground);
353
- const backgroundLuminance = relativeLuminance(background);
354
- if (foregroundLuminance === null || backgroundLuminance === null) return null;
355
- const lighter = Math.max(foregroundLuminance, backgroundLuminance);
356
- const darker = Math.min(foregroundLuminance, backgroundLuminance);
357
- return (lighter + 0.05) / (darker + 0.05);
358
- }
359
- function minimumContrastRatio(value, backgrounds) {
360
- const contrasts = backgrounds.map((background) => contrastRatio(value, background)).filter((contrast) => contrast !== null);
361
- if (contrasts.length !== backgrounds.length) return null;
362
- return Math.min(...contrasts);
363
- }
364
- function accessibleAccentTextColor(value) {
365
- if (!value) return void 0;
366
- const contrast = minimumContrastRatio(value, ["#f5f5f5", "#262626"]);
367
- if (contrast === null) return value;
368
- return contrast < 4.5 ? void 0 : value;
369
- }
370
- function ParticipantAvatar({
371
- participant
372
- }) {
373
- const isAgent = participant?.kind === "agent";
374
- const backgroundColor = participant?.color ?? (isAgent ? "var(--mieweb-primary-700, #1f2937)" : "#64748b");
375
- return /* @__PURE__ */ jsx(
376
- Avatar,
377
- {
378
- size: "xs",
379
- src: participant?.avatar,
380
- alt: "",
381
- name: participant?.name ?? "?",
382
- fallback: isAgent ? /* @__PURE__ */ jsx(SparklesIcon, { size: "sm" }) : void 0,
383
- style: { backgroundColor },
384
- "aria-hidden": "true",
385
- className: "shrink-0"
386
- }
387
- );
388
- }
389
- function ReferenceChip({
390
- reference,
391
- linkBuilder,
392
- onReferenceClick
393
- }) {
394
- const href = linkBuilder?.(reference);
395
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
396
- /* @__PURE__ */ jsx(
397
- Badge,
398
- {
399
- variant: "default",
400
- size: "sm",
401
- className: "rounded px-1.5 text-[10px] font-semibold tracking-wide uppercase",
402
- children: reference.refType
403
- }
404
- ),
405
- /* @__PURE__ */ jsx("span", { className: "truncate", children: reference.title })
406
- ] });
407
- const className = "inline-flex max-w-full items-center gap-2 rounded-lg border border-neutral-200 bg-white px-3 py-1.5 text-sm text-neutral-700 hover:border-primary-300 dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-200";
408
- if (href) {
409
- return /* @__PURE__ */ jsx(
410
- "a",
411
- {
412
- href,
413
- className,
414
- onClick: () => onReferenceClick?.(reference),
415
- children: content
229
+ href,
230
+ className,
231
+ onClick: () => onReferenceClick?.(reference),
232
+ children: content
416
233
  }
417
234
  );
418
235
  }
@@ -472,11 +289,11 @@ function useMessageCopy({
472
289
  getText,
473
290
  defaultFormat
474
291
  }) {
475
- const [copied, setCopied] = React2.useState(false);
476
- const copiedTimer = React2.useRef(
292
+ const [copied, setCopied] = React3.useState(false);
293
+ const copiedTimer = React3.useRef(
477
294
  void 0
478
295
  );
479
- React2.useEffect(() => () => window.clearTimeout(copiedTimer.current), []);
296
+ React3.useEffect(() => () => window.clearTimeout(copiedTimer.current), []);
480
297
  const flash = () => {
481
298
  setCopied(true);
482
299
  window.clearTimeout(copiedTimer.current);
@@ -529,7 +346,7 @@ function FooterActionButton({
529
346
  action,
530
347
  isSelf
531
348
  }) {
532
- const [open, setOpen] = React2.useState(false);
349
+ const [open, setOpen] = React3.useState(false);
533
350
  const onClickCapture = action.submenu ? (e) => {
534
351
  if (e.metaKey || e.ctrlKey) {
535
352
  e.preventDefault();
@@ -572,17 +389,13 @@ function FooterActionButton({
572
389
  }
573
390
  );
574
391
  }
575
- var MessageActionsBar = React2.forwardRef(function MessageActionsBar2({ actions, isSelf }, ref) {
392
+ var MessageActionsBar = React3.forwardRef(function MessageActionsBar2({ actions, isSelf }, ref) {
576
393
  return /* @__PURE__ */ jsx(
577
394
  "div",
578
395
  {
579
396
  ref,
580
397
  "data-slot": "superchat-message-actions",
581
- className: cn(
582
- "flex items-center gap-0.5",
583
- isSelf && "justify-end",
584
- actionRevealClass
585
- ),
398
+ className: cn("flex flex-col items-center gap-0.5", actionRevealClass),
586
399
  children: actions.map((action) => /* @__PURE__ */ jsx(FooterActionButton, { action, isSelf }, action.id))
587
400
  }
588
401
  );
@@ -592,7 +405,7 @@ function MessageOverflowMenu({
592
405
  actions,
593
406
  footerVisible
594
407
  }) {
595
- const [open, setOpen] = React2.useState(false);
408
+ const [open, setOpen] = React3.useState(false);
596
409
  const select = (fn) => {
597
410
  setOpen(false);
598
411
  fn();
@@ -601,7 +414,7 @@ function MessageOverflowMenu({
601
414
  "div",
602
415
  {
603
416
  className: cn(
604
- "sticky bottom-2 shrink-0 self-end transition-opacity",
417
+ "sticky bottom-2 mt-auto shrink-0 transition-opacity",
605
418
  // Rich content (e.g. NITRO tables) layers internals up to z-50, so the
606
419
  // open menu's stacking context must clear that.
607
420
  open ? "z-[60]" : "z-10",
@@ -645,7 +458,7 @@ function MessageOverflowMenu({
645
458
  }
646
459
  );
647
460
  }
648
- var MessageRow = React2.memo(function MessageRow2({
461
+ var MessageRow = React3.memo(function MessageRow2({
649
462
  message,
650
463
  participant,
651
464
  isSelf,
@@ -654,21 +467,27 @@ var MessageRow = React2.memo(function MessageRow2({
654
467
  onReferenceClick,
655
468
  editable,
656
469
  onMessageEdited,
657
- defaultCopyFormat = "rich"
470
+ defaultCopyFormat = "rich",
471
+ onOpenMedia,
472
+ openMediaLabel = "Open in media feed",
473
+ playMediaLabel = "Play",
474
+ mediaErrorLabel,
475
+ mediaRetryLabel
658
476
  }) {
659
477
  const streaming = message.status === "streaming";
660
- const hasBody = !!message.text || (message.content?.length ?? 0) > 0;
661
- const [isEditing, setIsEditing] = React2.useState(false);
662
- const [draft, setDraft] = React2.useState(message.text ?? "");
663
- const editRef = React2.useRef(null);
664
- const bubbleRef = React2.useRef(null);
665
- const autosize = React2.useCallback(() => {
478
+ const hasBody = !!message.text || (message.content?.length ?? 0) > 0 || (message.media?.length ?? 0) > 0;
479
+ const [isEditing, setIsEditing] = React3.useState(false);
480
+ const [draft, setDraft] = React3.useState(message.text ?? "");
481
+ const [editMinWidth, setEditMinWidth] = React3.useState();
482
+ const editRef = React3.useRef(null);
483
+ const bubbleRef = React3.useRef(null);
484
+ const autosize = React3.useCallback(() => {
666
485
  const el = editRef.current;
667
486
  if (!el) return;
668
487
  el.style.height = "auto";
669
488
  el.style.height = `${el.scrollHeight}px`;
670
489
  }, []);
671
- React2.useEffect(() => {
490
+ React3.useEffect(() => {
672
491
  if (!isEditing) return;
673
492
  const el = editRef.current;
674
493
  if (!el) return;
@@ -683,337 +502,662 @@ var MessageRow = React2.memo(function MessageRow2({
683
502
  ${block.text}
684
503
  \`\`\``;
685
504
  }
686
- if ((block.type === "text" || block.type === "thinking") && block.text) {
687
- return block.text;
505
+ if ((block.type === "text" || block.type === "thinking") && block.text) {
506
+ return block.text;
507
+ }
508
+ return "";
509
+ }).filter(Boolean).join("\n\n") ?? "";
510
+ const canCopy = !isEditing && (!!message.content?.length || typeof message.text === "string" && message.text.length > 0);
511
+ const showEditAction = canEdit && !isEditing;
512
+ const actionCount = (canCopy ? 1 : 0) + (showEditAction ? 1 : 0);
513
+ const hasActions = actionCount > 0;
514
+ const collapseToMenu = actionCount > 1;
515
+ const copy = useMessageCopy({
516
+ markdown: markdownSource,
517
+ getHtml: () => bubbleRef.current?.innerHTML ?? "",
518
+ getText: () => bubbleRef.current?.textContent ?? "",
519
+ defaultFormat: defaultCopyFormat
520
+ });
521
+ const actionsBarRef = React3.useRef(null);
522
+ const [footerVisible, setFooterVisible] = React3.useState(true);
523
+ React3.useEffect(() => {
524
+ const el = actionsBarRef.current;
525
+ if (!el || typeof globalThis.IntersectionObserver === "undefined") return;
526
+ const observer = new globalThis.IntersectionObserver(([entry]) => {
527
+ setFooterVisible(entry?.isIntersecting ?? false);
528
+ });
529
+ observer.observe(el);
530
+ return () => observer.disconnect();
531
+ }, [hasActions, collapseToMenu]);
532
+ if (message.type === "system") {
533
+ return /* @__PURE__ */ jsx(
534
+ "div",
535
+ {
536
+ "data-slot": "superchat-system-message",
537
+ role: "status",
538
+ className: "my-1 text-center text-xs text-neutral-500 dark:text-neutral-400",
539
+ children: message.text
540
+ }
541
+ );
542
+ }
543
+ if (message.type === "ref" && message.ref) {
544
+ return /* @__PURE__ */ jsx(
545
+ "div",
546
+ {
547
+ "data-slot": "superchat-reference",
548
+ className: cn("flex", isSelf && "justify-end"),
549
+ children: /* @__PURE__ */ jsx(
550
+ ReferenceChip,
551
+ {
552
+ reference: message.ref,
553
+ linkBuilder,
554
+ onReferenceClick
555
+ }
556
+ )
557
+ }
558
+ );
559
+ }
560
+ const accent = participant?.color;
561
+ const accentTextColor = accessibleAccentTextColor(accent);
562
+ const authorName = participant?.name ?? "Unknown";
563
+ const startEdit = () => {
564
+ const el = bubbleRef.current;
565
+ if (el) {
566
+ const cs = getComputedStyle(el);
567
+ const contentWidth = el.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight);
568
+ setEditMinWidth(contentWidth > 0 ? contentWidth : void 0);
569
+ }
570
+ setDraft(message.text ?? "");
571
+ setIsEditing(true);
572
+ };
573
+ const cancelEdit = () => setIsEditing(false);
574
+ const saveEdit = () => {
575
+ const next = draft.trim();
576
+ if (next && next !== message.text) onMessageEdited?.(message.id, next);
577
+ setIsEditing(false);
578
+ };
579
+ const handleEditPaste = (e) => {
580
+ const files = Array.from(e.clipboardData.items).filter((item) => item.kind === "file" && item.type.startsWith("image/")).map((item) => item.getAsFile()).filter((f) => f !== null);
581
+ if (files.length === 0) return;
582
+ e.preventDefault();
583
+ const el = e.currentTarget;
584
+ const start = el.selectionStart ?? draft.length;
585
+ const end = el.selectionEnd ?? draft.length;
586
+ Promise.all(
587
+ files.map(
588
+ (file, i) => new Promise((resolve) => {
589
+ const reader = new window.FileReader();
590
+ reader.onload = () => {
591
+ const dataUrl = typeof reader.result === "string" ? reader.result : "";
592
+ const name = file.name || `pasted-image-${i + 1}.png`;
593
+ resolve(dataUrl ? `![${name}](${dataUrl})` : "");
594
+ };
595
+ reader.readAsDataURL(file);
596
+ })
597
+ )
598
+ ).then((snippets) => {
599
+ const insert = snippets.filter(Boolean).join("\n");
600
+ if (!insert) return;
601
+ el.focus();
602
+ el.setSelectionRange(start, end);
603
+ const text = `${insert}
604
+ `;
605
+ const inserted = typeof document !== "undefined" && typeof document.execCommand === "function" && document.execCommand("insertText", false, text);
606
+ if (!inserted) {
607
+ setDraft((prev) => `${prev.slice(0, start)}${text}${prev.slice(end)}`);
608
+ }
609
+ requestAnimationFrame(autosize);
610
+ });
611
+ };
612
+ const actions = [
613
+ ...canCopy ? [
614
+ {
615
+ id: "copy",
616
+ label: "Copy message",
617
+ title: "Copy message (\u2318/Ctrl-click: default format)",
618
+ icon: copy.copied ? /* @__PURE__ */ jsx(Check, { size: 14, "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Clipboard, { size: 14, "aria-hidden": "true" }),
619
+ onSelect: copy.copyDefault,
620
+ submenu: {
621
+ label: "Copy as",
622
+ items: [
623
+ {
624
+ id: "copy-rich",
625
+ label: "Copy as rich text",
626
+ description: "Rich text + Markdown",
627
+ onSelect: copy.copyRich
628
+ },
629
+ {
630
+ id: "copy-markdown",
631
+ label: "Copy as Markdown",
632
+ onSelect: copy.copyMarkdown
633
+ },
634
+ {
635
+ id: "copy-plain",
636
+ label: "Copy as plain text",
637
+ onSelect: copy.copyPlain
638
+ }
639
+ ]
640
+ }
641
+ }
642
+ ] : [],
643
+ ...showEditAction ? [
644
+ {
645
+ id: "edit",
646
+ label: "Edit message",
647
+ icon: /* @__PURE__ */ jsx(Pencil, { size: 14, "aria-hidden": "true" }),
648
+ onSelect: startEdit
649
+ }
650
+ ] : []
651
+ ];
652
+ return /* @__PURE__ */ jsxs(
653
+ "div",
654
+ {
655
+ "data-slot": "superchat-message",
656
+ role: "article",
657
+ "aria-label": `${authorName}, ${formatTime(message.time)}`,
658
+ className: cn(
659
+ "group flex gap-2",
660
+ isSelf ? "flex-row-reverse" : "flex-row"
661
+ ),
662
+ children: [
663
+ /* @__PURE__ */ jsxs(
664
+ "div",
665
+ {
666
+ "data-slot": "superchat-message-gutter",
667
+ className: "flex shrink-0 flex-col items-center gap-1",
668
+ children: [
669
+ /* @__PURE__ */ jsx(ParticipantAvatar, { participant }),
670
+ hasActions && /* @__PURE__ */ jsxs(Fragment, { children: [
671
+ /* @__PURE__ */ jsx(
672
+ MessageOverflowMenu,
673
+ {
674
+ isSelf,
675
+ actions,
676
+ footerVisible: collapseToMenu ? false : footerVisible
677
+ }
678
+ ),
679
+ !collapseToMenu && /* @__PURE__ */ jsx(
680
+ MessageActionsBar,
681
+ {
682
+ ref: actionsBarRef,
683
+ actions,
684
+ isSelf
685
+ }
686
+ )
687
+ ] })
688
+ ]
689
+ }
690
+ ),
691
+ /* @__PURE__ */ jsxs(
692
+ "div",
693
+ {
694
+ className: cn(
695
+ "flex min-w-0 flex-1 flex-col gap-1",
696
+ isSelf && "items-end"
697
+ ),
698
+ children: [
699
+ /* @__PURE__ */ jsxs(
700
+ "div",
701
+ {
702
+ "data-slot": "superchat-message-meta",
703
+ className: "flex items-baseline gap-2",
704
+ children: [
705
+ /* @__PURE__ */ jsx(
706
+ "span",
707
+ {
708
+ className: "text-xs font-medium",
709
+ style: accentTextColor ? { color: accentTextColor } : void 0,
710
+ children: authorName
711
+ }
712
+ ),
713
+ participant?.role && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-500 dark:text-neutral-400", children: participant.role }),
714
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-500 dark:text-neutral-400", children: formatTime(message.time) }),
715
+ message.editedAt && /* @__PURE__ */ jsx(
716
+ "span",
717
+ {
718
+ "data-slot": "superchat-edited-indicator",
719
+ className: "text-[10px] text-neutral-500 dark:text-neutral-400",
720
+ title: `Edited ${formatTime(message.editedAt)}`,
721
+ children: "(edited)"
722
+ }
723
+ )
724
+ ]
725
+ }
726
+ ),
727
+ /* @__PURE__ */ jsx(
728
+ "div",
729
+ {
730
+ className: cn(
731
+ "flex w-full items-center gap-1",
732
+ isSelf ? "flex-row-reverse" : "flex-row"
733
+ ),
734
+ children: /* @__PURE__ */ jsx(
735
+ ChatBubble,
736
+ {
737
+ ref: bubbleRef,
738
+ "data-slot": "superchat-bubble",
739
+ variant: isSelf ? "user" : "assistant",
740
+ hasError: message.status === "error",
741
+ className: "text-sm has-[[data-slot=superchat-nitro-table]]:w-full has-[[data-slot=superchat-nitro-table]]:max-w-full",
742
+ children: isEditing ? /* @__PURE__ */ jsxs(
743
+ "div",
744
+ {
745
+ "data-slot": "superchat-message-editor",
746
+ className: "flex w-80 max-w-full flex-col gap-2",
747
+ style: editMinWidth ? { minWidth: editMinWidth } : void 0,
748
+ children: [
749
+ /* @__PURE__ */ jsx(
750
+ "textarea",
751
+ {
752
+ value: draft,
753
+ ref: editRef,
754
+ rows: 2,
755
+ onChange: (e) => {
756
+ setDraft(e.target.value);
757
+ autosize();
758
+ },
759
+ onPaste: handleEditPaste,
760
+ onKeyDown: (e) => {
761
+ if (e.key === "Enter" && !e.shiftKey) {
762
+ e.preventDefault();
763
+ saveEdit();
764
+ } else if (e.key === "Escape") {
765
+ e.preventDefault();
766
+ cancelEdit();
767
+ }
768
+ },
769
+ "aria-label": "Edit message",
770
+ className: "focus:ring-primary-500 max-h-60 min-h-16 w-full resize-none rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm text-neutral-900 focus:ring-1 focus:outline-none dark:border-neutral-600 dark:bg-neutral-900 dark:text-white"
771
+ }
772
+ ),
773
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
774
+ /* @__PURE__ */ jsx(
775
+ "button",
776
+ {
777
+ type: "button",
778
+ onClick: cancelEdit,
779
+ className: "rounded-md px-2.5 py-1 text-xs font-medium text-neutral-200 hover:bg-white/10",
780
+ children: "Cancel"
781
+ }
782
+ ),
783
+ /* @__PURE__ */ jsx(
784
+ "button",
785
+ {
786
+ type: "button",
787
+ onClick: saveEdit,
788
+ disabled: !draft.trim() || draft.trim() === message.text,
789
+ className: "rounded-md bg-white px-2.5 py-1 text-xs font-medium text-neutral-900 hover:bg-neutral-100 disabled:opacity-40",
790
+ children: "Save"
791
+ }
792
+ )
793
+ ] })
794
+ ]
795
+ }
796
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
797
+ message.content?.map((block, i) => {
798
+ if (block.type === "tool_use" && block.toolCall) {
799
+ return /* @__PURE__ */ jsx(MCPToolCallDisplay, { toolCall: block.toolCall }, i);
800
+ }
801
+ if ((block.type === "text" || block.type === "thinking") && block.text) {
802
+ return /* @__PURE__ */ jsx(
803
+ "div",
804
+ {
805
+ className: "prose prose-sm dark:prose-invert max-w-none **:wrap-break-word",
806
+ children: renderText(block.text, {
807
+ messageId: message.id,
808
+ streaming,
809
+ role: participant?.kind === "human" ? "user" : "assistant"
810
+ })
811
+ },
812
+ i
813
+ );
814
+ }
815
+ if (block.type === "code" && block.text) {
816
+ const fenced = `\`\`\`${block.language ?? ""}
817
+ ${block.text}
818
+ \`\`\``;
819
+ return /* @__PURE__ */ jsx(
820
+ "div",
821
+ {
822
+ className: "prose prose-sm dark:prose-invert max-w-none **:wrap-break-word",
823
+ children: renderText(fenced, {
824
+ messageId: message.id,
825
+ streaming,
826
+ role: participant?.kind === "human" ? "user" : "assistant"
827
+ })
828
+ },
829
+ i
830
+ );
831
+ }
832
+ return null;
833
+ }),
834
+ message.text && /* @__PURE__ */ jsx("div", { className: "prose prose-sm dark:prose-invert max-w-none **:wrap-break-word", children: renderText(message.text, {
835
+ messageId: message.id,
836
+ streaming,
837
+ role: participant?.kind === "human" ? "user" : "assistant"
838
+ }) }),
839
+ message.media?.map((attachment) => /* @__PURE__ */ jsx(
840
+ MessageMedia,
841
+ {
842
+ attachment,
843
+ openLabel: openMediaLabel,
844
+ playLabel: playMediaLabel,
845
+ errorLabel: mediaErrorLabel,
846
+ retryLabel: mediaRetryLabel,
847
+ launchId: JSON.stringify([message.id, attachment.id]),
848
+ onOpen: onOpenMedia ? (play) => onOpenMedia(message.id, attachment.id, play) : void 0
849
+ },
850
+ attachment.id
851
+ )),
852
+ streaming && !hasBody && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx(AITypingIndicator, {}) })
853
+ ] })
854
+ }
855
+ )
856
+ }
857
+ )
858
+ ]
859
+ }
860
+ )
861
+ ]
862
+ }
863
+ );
864
+ });
865
+ var sidebarItem = cva(
866
+ "flex w-full items-center gap-2 rounded-lg px-3 py-2 text-start text-sm transition-colors",
867
+ {
868
+ variants: {
869
+ active: {
870
+ true: "bg-primary-100 text-primary-900 dark:bg-primary-900/40 dark:text-primary-100",
871
+ false: "text-neutral-700 hover:bg-neutral-100 dark:text-neutral-200 dark:hover:bg-neutral-800"
872
+ }
873
+ },
874
+ defaultVariants: { active: false }
875
+ }
876
+ );
877
+
878
+ // src/components/SuperChat/media.ts
879
+ function getConversationMediaItems(conversation) {
880
+ const participants = new Map(
881
+ conversation.participants.map((participant) => [
882
+ participant.id,
883
+ participant
884
+ ])
885
+ );
886
+ return [...conversation.thread].sort(byTime).flatMap(
887
+ (message) => (message.media ?? []).map((attachment) => ({
888
+ // Tuple encoding prevents collisions when ids themselves contain a
889
+ // delimiter. Including the conversation keeps selection scoped to it.
890
+ id: JSON.stringify([conversation.id, message.id, attachment.id]),
891
+ conversationId: conversation.id,
892
+ message,
893
+ attachment,
894
+ participant: participants.get(message.participantId)
895
+ }))
896
+ );
897
+ }
898
+ function remarkPreserveLineBreaks() {
899
+ const splitNode = (node) => {
900
+ if (!node.children) return;
901
+ const next = [];
902
+ for (const child of node.children) {
903
+ if (child.type === "text" && child.value && child.value.includes("\n")) {
904
+ const segments = child.value.split("\n");
905
+ segments.forEach((segment, i) => {
906
+ if (i > 0) next.push({ type: "break" });
907
+ if (segment) next.push({ type: "text", value: segment });
908
+ });
909
+ } else {
910
+ splitNode(child);
911
+ next.push(child);
912
+ }
913
+ }
914
+ node.children = next;
915
+ };
916
+ return (tree) => splitNode(tree);
917
+ }
918
+ function baseSanitizeSchema() {
919
+ const schema = JSON.parse(JSON.stringify(defaultSchema));
920
+ const attributes = schema.attributes ?? {};
921
+ const allowClass = (tag) => {
922
+ const existing = attributes[tag] ?? [];
923
+ const withoutClass = existing.filter(
924
+ (a) => !(Array.isArray(a) && a[0] === "className")
925
+ );
926
+ attributes[tag] = [...withoutClass, "className"];
927
+ };
928
+ allowClass("code");
929
+ allowClass("pre");
930
+ allowClass("span");
931
+ allowClass("div");
932
+ schema.attributes = attributes;
933
+ return schema;
934
+ }
935
+ function mergeSanitizeSchema(base, extra) {
936
+ if (!extra) return base;
937
+ const out = { ...base };
938
+ if (Array.isArray(extra.tagNames)) {
939
+ const a = base.tagNames ?? [];
940
+ out.tagNames = Array.from(/* @__PURE__ */ new Set([...a, ...extra.tagNames]));
941
+ }
942
+ if (extra.attributes && typeof extra.attributes === "object") {
943
+ const baseAttrs = {
944
+ ...base.attributes ?? {}
945
+ };
946
+ for (const [tag, attrs] of Object.entries(
947
+ extra.attributes
948
+ )) {
949
+ baseAttrs[tag] = [...baseAttrs[tag] ?? [], ...attrs];
950
+ }
951
+ out.attributes = baseAttrs;
952
+ }
953
+ if (extra.protocols && typeof extra.protocols === "object") {
954
+ const baseProtocols = {
955
+ ...base.protocols ?? {}
956
+ };
957
+ for (const [attr, protocols] of Object.entries(
958
+ extra.protocols
959
+ )) {
960
+ baseProtocols[attr] = Array.from(
961
+ /* @__PURE__ */ new Set([...baseProtocols[attr] ?? [], ...protocols])
962
+ );
688
963
  }
689
- return "";
690
- }).filter(Boolean).join("\n\n") ?? "";
691
- const canCopy = !isEditing && (!!message.content?.length || typeof message.text === "string" && message.text.length > 0);
692
- const hasActions = canCopy || canEdit && !isEditing;
693
- const copy = useMessageCopy({
694
- markdown: markdownSource,
695
- getHtml: () => bubbleRef.current?.innerHTML ?? "",
696
- getText: () => bubbleRef.current?.textContent ?? "",
697
- defaultFormat: defaultCopyFormat
698
- });
699
- const actionsBarRef = React2.useRef(null);
700
- const [footerVisible, setFooterVisible] = React2.useState(true);
701
- React2.useEffect(() => {
702
- const el = actionsBarRef.current;
703
- if (!el || typeof globalThis.IntersectionObserver === "undefined") return;
704
- const observer = new globalThis.IntersectionObserver(([entry]) => {
705
- setFooterVisible(entry?.isIntersecting ?? false);
706
- });
707
- observer.observe(el);
708
- return () => observer.disconnect();
709
- }, [hasActions]);
710
- if (message.type === "system") {
711
- return /* @__PURE__ */ jsx(
712
- "div",
964
+ out.protocols = baseProtocols;
965
+ }
966
+ for (const [k, v] of Object.entries(extra)) {
967
+ if (k === "tagNames" || k === "attributes" || k === "protocols") continue;
968
+ out[k] = v;
969
+ }
970
+ return out;
971
+ }
972
+ function baseComponents() {
973
+ return {
974
+ a: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
975
+ "a",
713
976
  {
714
- "data-slot": "superchat-system-message",
715
- role: "status",
716
- className: "my-1 text-center text-xs text-neutral-500 dark:text-neutral-400",
717
- children: message.text
977
+ ...props,
978
+ className: cn(
979
+ "text-primary-800 hover:text-primary-900 dark:text-primary-300 underline underline-offset-2",
980
+ props.className
981
+ ),
982
+ target: props.target ?? "_blank",
983
+ rel: props.rel ?? "noopener noreferrer",
984
+ children
718
985
  }
719
- );
720
- }
721
- if (message.type === "ref" && message.ref) {
722
- return /* @__PURE__ */ jsx(
723
- "div",
986
+ ),
987
+ pre: ({ node: _node, ...props }) => /* @__PURE__ */ jsx(
988
+ "pre",
724
989
  {
725
- "data-slot": "superchat-reference",
726
- className: cn("flex", isSelf && "justify-end"),
727
- children: /* @__PURE__ */ jsx(
728
- ReferenceChip,
990
+ ...props,
991
+ tabIndex: 0,
992
+ className: cn(
993
+ "overflow-x-auto rounded-lg bg-neutral-900 p-3 text-sm text-neutral-100 dark:bg-neutral-950",
994
+ props.className
995
+ )
996
+ }
997
+ ),
998
+ code: ({ node: _node, ...props }) => {
999
+ const isBlock = typeof props.className === "string" && props.className.includes("language-");
1000
+ return /* @__PURE__ */ jsx(
1001
+ "code",
1002
+ {
1003
+ ...props,
1004
+ className: cn(
1005
+ !isBlock && "rounded bg-neutral-200 px-1 py-0.5 text-[0.85em] text-neutral-800 dark:bg-neutral-700 dark:text-neutral-100",
1006
+ props.className
1007
+ )
1008
+ }
1009
+ );
1010
+ },
1011
+ input: ({ node: _node, ...props }) => {
1012
+ if (props.type === "checkbox") {
1013
+ return /* @__PURE__ */ jsx(
1014
+ "input",
729
1015
  {
730
- reference: message.ref,
731
- linkBuilder,
732
- onReferenceClick
1016
+ ...props,
1017
+ "aria-label": props["aria-label"] ?? (props["aria-labelledby"] ? void 0 : "Task list item")
733
1018
  }
1019
+ );
1020
+ }
1021
+ return /* @__PURE__ */ jsx("input", { ...props });
1022
+ },
1023
+ table: ({ node: _node, ...props }) => /* @__PURE__ */ jsx("div", { className: "my-2 overflow-x-auto", children: /* @__PURE__ */ jsx(
1024
+ "table",
1025
+ {
1026
+ ...props,
1027
+ className: cn(
1028
+ "w-full border-collapse text-sm [&_td]:border [&_td]:border-neutral-200 [&_td]:px-2 [&_td]:py-1 dark:[&_td]:border-neutral-700 [&_th]:border [&_th]:border-neutral-200 [&_th]:px-2 [&_th]:py-1 [&_th]:text-start dark:[&_th]:border-neutral-700",
1029
+ props.className
734
1030
  )
735
1031
  }
736
- );
737
- }
738
- const accent = participant?.color;
739
- const accentTextColor = accessibleAccentTextColor(accent);
740
- const authorName = participant?.name ?? "Unknown";
741
- const startEdit = () => {
742
- setDraft(message.text ?? "");
743
- setIsEditing(true);
744
- };
745
- const cancelEdit = () => setIsEditing(false);
746
- const saveEdit = () => {
747
- const next = draft.trim();
748
- if (next && next !== message.text) onMessageEdited?.(message.id, next);
749
- setIsEditing(false);
750
- };
751
- const handleEditPaste = (e) => {
752
- const files = Array.from(e.clipboardData.items).filter((item) => item.kind === "file" && item.type.startsWith("image/")).map((item) => item.getAsFile()).filter((f) => f !== null);
753
- if (files.length === 0) return;
754
- e.preventDefault();
755
- const el = e.currentTarget;
756
- const start = el.selectionStart ?? draft.length;
757
- const end = el.selectionEnd ?? draft.length;
758
- Promise.all(
759
- files.map(
760
- (file, i) => new Promise((resolve) => {
761
- const reader = new window.FileReader();
762
- reader.onload = () => {
763
- const dataUrl = typeof reader.result === "string" ? reader.result : "";
764
- const name = file.name || `pasted-image-${i + 1}.png`;
765
- resolve(dataUrl ? `![${name}](${dataUrl})` : "");
766
- };
767
- reader.readAsDataURL(file);
768
- })
769
- )
770
- ).then((snippets) => {
771
- const insert = snippets.filter(Boolean).join("\n");
772
- if (!insert) return;
773
- el.focus();
774
- el.setSelectionRange(start, end);
775
- const text = `${insert}
776
- `;
777
- const inserted = typeof document !== "undefined" && typeof document.execCommand === "function" && document.execCommand("insertText", false, text);
778
- if (!inserted) {
779
- setDraft((prev) => `${prev.slice(0, start)}${text}${prev.slice(end)}`);
1032
+ ) }),
1033
+ // Tailwind's preflight resets list markers/padding; restore them explicitly
1034
+ // so bullets/numbers show without depending on the typography plugin.
1035
+ ul: ({ node: _node, ...props }) => /* @__PURE__ */ jsx("ul", { ...props, className: cn("list-disc ps-5", props.className) }),
1036
+ ol: ({ node: _node, ...props }) => /* @__PURE__ */ jsx("ol", { ...props, className: cn("list-decimal ps-5", props.className) }),
1037
+ li: ({ node: _node, ...props }) => /* @__PURE__ */ jsx("li", { ...props, className: cn("ps-1", props.className) }),
1038
+ // Preflight also flattens headings to body size/weight; restore a sensible
1039
+ // hierarchy without depending on the typography plugin.
1040
+ h1: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
1041
+ "h1",
1042
+ {
1043
+ ...props,
1044
+ className: cn("mt-3 mb-1 text-xl font-semibold", props.className),
1045
+ children
780
1046
  }
781
- requestAnimationFrame(autosize);
782
- });
783
- };
784
- const actions = [
785
- ...canCopy ? [
1047
+ ),
1048
+ h2: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
1049
+ "h2",
786
1050
  {
787
- id: "copy",
788
- label: "Copy message",
789
- title: "Copy message (\u2318/Ctrl-click: default format)",
790
- icon: copy.copied ? /* @__PURE__ */ jsx(Check, { size: 14, "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Clipboard, { size: 14, "aria-hidden": "true" }),
791
- onSelect: copy.copyDefault,
792
- submenu: {
793
- label: "Copy as",
794
- items: [
795
- {
796
- id: "copy-rich",
797
- label: "Copy as rich text",
798
- description: "Rich text + Markdown",
799
- onSelect: copy.copyRich
800
- },
801
- {
802
- id: "copy-markdown",
803
- label: "Copy as Markdown",
804
- onSelect: copy.copyMarkdown
805
- },
806
- {
807
- id: "copy-plain",
808
- label: "Copy as plain text",
809
- onSelect: copy.copyPlain
810
- }
811
- ]
812
- }
1051
+ ...props,
1052
+ className: cn("mt-3 mb-1 text-lg font-semibold", props.className),
1053
+ children
1054
+ }
1055
+ ),
1056
+ h3: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
1057
+ "h3",
1058
+ {
1059
+ ...props,
1060
+ className: cn("mt-2 mb-1 text-base font-semibold", props.className),
1061
+ children
1062
+ }
1063
+ ),
1064
+ h4: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
1065
+ "h4",
1066
+ {
1067
+ ...props,
1068
+ className: cn("mt-2 mb-1 text-sm font-semibold", props.className),
1069
+ children
813
1070
  }
814
- ] : [],
815
- ...canEdit && !isEditing ? [
1071
+ ),
1072
+ h5: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
1073
+ "h5",
816
1074
  {
817
- id: "edit",
818
- label: "Edit message",
819
- icon: /* @__PURE__ */ jsx(Pencil, { size: 14, "aria-hidden": "true" }),
820
- onSelect: startEdit
1075
+ ...props,
1076
+ className: cn("mt-2 mb-1 text-sm font-semibold", props.className),
1077
+ children
821
1078
  }
822
- ] : []
1079
+ ),
1080
+ h6: ({ node: _node, children, ...props }) => /* @__PURE__ */ jsx(
1081
+ "h6",
1082
+ {
1083
+ ...props,
1084
+ className: cn(
1085
+ "mt-2 mb-1 text-xs font-semibold tracking-wide uppercase",
1086
+ props.className
1087
+ ),
1088
+ children
1089
+ }
1090
+ ),
1091
+ hr: ({ node: _node, ...props }) => /* @__PURE__ */ jsx(
1092
+ "hr",
1093
+ {
1094
+ ...props,
1095
+ className: cn(
1096
+ "my-2 border-neutral-300 dark:border-neutral-600",
1097
+ props.className
1098
+ )
1099
+ }
1100
+ )
1101
+ };
1102
+ }
1103
+ function createMarkdownRenderer(options = {}) {
1104
+ const { plugins = [], trusted = false } = options;
1105
+ const remarkPlugins = [
1106
+ remarkGfm,
1107
+ remarkPreserveLineBreaks,
1108
+ ...plugins.flatMap((p) => p.remarkPlugins ?? [])
823
1109
  ];
824
- return /* @__PURE__ */ jsxs(
825
- "div",
826
- {
827
- "data-slot": "superchat-message",
828
- role: "article",
829
- "aria-label": `${authorName}, ${formatTime(message.time)}`,
830
- className: cn(
831
- "group flex gap-2",
832
- isSelf ? "flex-row-reverse" : "flex-row"
833
- ),
834
- children: [
835
- /* @__PURE__ */ jsx(ParticipantAvatar, { participant }),
836
- /* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 flex-col gap-1", isSelf && "items-end"), children: [
837
- /* @__PURE__ */ jsxs(
838
- "div",
839
- {
840
- "data-slot": "superchat-message-meta",
841
- className: "flex items-baseline gap-2",
842
- children: [
843
- /* @__PURE__ */ jsx(
844
- "span",
845
- {
846
- className: "text-xs font-medium",
847
- style: accentTextColor ? { color: accentTextColor } : void 0,
848
- children: authorName
849
- }
850
- ),
851
- participant?.role && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-500 dark:text-neutral-400", children: participant.role }),
852
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-500 dark:text-neutral-400", children: formatTime(message.time) }),
853
- message.editedAt && /* @__PURE__ */ jsx(
854
- "span",
855
- {
856
- "data-slot": "superchat-edited-indicator",
857
- className: "text-[10px] text-neutral-500 dark:text-neutral-400",
858
- title: `Edited ${formatTime(message.editedAt)}`,
859
- children: "(edited)"
860
- }
861
- )
862
- ]
863
- }
864
- ),
865
- /* @__PURE__ */ jsxs(
866
- "div",
867
- {
868
- className: cn(
869
- "flex items-center gap-1",
870
- isSelf ? "flex-row-reverse" : "flex-row"
871
- ),
872
- children: [
873
- hasActions && /* @__PURE__ */ jsx(
874
- MessageOverflowMenu,
875
- {
876
- isSelf,
877
- actions,
878
- footerVisible
879
- }
880
- ),
881
- /* @__PURE__ */ jsx(
882
- ChatBubble,
883
- {
884
- ref: bubbleRef,
885
- "data-slot": "superchat-bubble",
886
- variant: isSelf ? "user" : "assistant",
887
- hasError: message.status === "error",
888
- className: "text-sm has-[[data-slot=superchat-nitro-table]]:w-full has-[[data-slot=superchat-nitro-table]]:max-w-full",
889
- children: isEditing ? /* @__PURE__ */ jsxs(
890
- "div",
891
- {
892
- "data-slot": "superchat-message-editor",
893
- className: "flex w-80 max-w-full flex-col gap-2",
894
- children: [
895
- /* @__PURE__ */ jsx(
896
- "textarea",
897
- {
898
- value: draft,
899
- ref: editRef,
900
- rows: 2,
901
- onChange: (e) => {
902
- setDraft(e.target.value);
903
- autosize();
904
- },
905
- onPaste: handleEditPaste,
906
- onKeyDown: (e) => {
907
- if (e.key === "Enter" && !e.shiftKey) {
908
- e.preventDefault();
909
- saveEdit();
910
- } else if (e.key === "Escape") {
911
- e.preventDefault();
912
- cancelEdit();
913
- }
914
- },
915
- "aria-label": "Edit message",
916
- className: "focus:ring-primary-500 max-h-60 min-h-16 w-full resize-none rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm text-neutral-900 focus:ring-1 focus:outline-none dark:border-neutral-600 dark:bg-neutral-900 dark:text-white"
917
- }
918
- ),
919
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
920
- /* @__PURE__ */ jsx(
921
- "button",
922
- {
923
- type: "button",
924
- onClick: cancelEdit,
925
- className: "rounded-md px-2.5 py-1 text-xs font-medium text-neutral-200 hover:bg-white/10",
926
- children: "Cancel"
927
- }
928
- ),
929
- /* @__PURE__ */ jsx(
930
- "button",
931
- {
932
- type: "button",
933
- onClick: saveEdit,
934
- disabled: !draft.trim() || draft.trim() === message.text,
935
- className: "rounded-md bg-white px-2.5 py-1 text-xs font-medium text-neutral-900 hover:bg-neutral-100 disabled:opacity-40",
936
- children: "Save"
937
- }
938
- )
939
- ] })
940
- ]
941
- }
942
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
943
- message.content?.map((block, i) => {
944
- if (block.type === "tool_use" && block.toolCall) {
945
- return /* @__PURE__ */ jsx(MCPToolCallDisplay, { toolCall: block.toolCall }, i);
946
- }
947
- if ((block.type === "text" || block.type === "thinking") && block.text) {
948
- return /* @__PURE__ */ jsx(
949
- "div",
950
- {
951
- className: "prose prose-sm dark:prose-invert max-w-none **:wrap-break-word",
952
- children: renderText(block.text, {
953
- messageId: message.id,
954
- streaming,
955
- role: participant?.kind === "human" ? "user" : "assistant"
956
- })
957
- },
958
- i
959
- );
960
- }
961
- if (block.type === "code" && block.text) {
962
- const fenced = `\`\`\`${block.language ?? ""}
963
- ${block.text}
964
- \`\`\``;
965
- return /* @__PURE__ */ jsx(
966
- "div",
967
- {
968
- className: "prose prose-sm dark:prose-invert max-w-none **:wrap-break-word",
969
- children: renderText(fenced, {
970
- messageId: message.id,
971
- streaming,
972
- role: participant?.kind === "human" ? "user" : "assistant"
973
- })
974
- },
975
- i
976
- );
977
- }
978
- return null;
979
- }),
980
- message.text && /* @__PURE__ */ jsx("div", { className: "prose prose-sm dark:prose-invert max-w-none **:wrap-break-word", children: renderText(message.text, {
981
- messageId: message.id,
982
- streaming,
983
- role: participant?.kind === "human" ? "user" : "assistant"
984
- }) }),
985
- streaming && !hasBody && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx(AITypingIndicator, {}) })
986
- ] })
987
- }
988
- )
989
- ]
990
- }
991
- ),
992
- hasActions && /* @__PURE__ */ jsx(
993
- MessageActionsBar,
994
- {
995
- ref: actionsBarRef,
996
- actions,
997
- isSelf
998
- }
999
- )
1000
- ] })
1001
- ]
1002
- }
1110
+ const pluginRehype = plugins.flatMap(
1111
+ (p) => p.rehypePlugins ?? []
1003
1112
  );
1004
- });
1005
- var sidebarItem = cva(
1006
- "flex w-full items-center gap-2 rounded-lg px-3 py-2 text-start text-sm transition-colors",
1007
- {
1008
- variants: {
1009
- active: {
1010
- true: "bg-primary-100 text-primary-900 dark:bg-primary-900/40 dark:text-primary-100",
1011
- false: "text-neutral-700 hover:bg-neutral-100 dark:text-neutral-200 dark:hover:bg-neutral-800"
1012
- }
1113
+ const sanitizeSchema = plugins.reduce(
1114
+ (acc, p) => mergeSanitizeSchema(acc, p.sanitizeSchema),
1115
+ baseSanitizeSchema()
1116
+ );
1117
+ const rehypePlugins = trusted ? pluginRehype : [...pluginRehype, [rehypeSanitize, sanitizeSchema]];
1118
+ const components = plugins.reduce(
1119
+ (acc, p) => ({ ...acc, ...p.components }),
1120
+ baseComponents()
1121
+ );
1122
+ const MarkdownRenderer = (text, ctx) => /* @__PURE__ */ jsx(
1123
+ MarkdownContent,
1124
+ {
1125
+ text,
1126
+ messageId: ctx.messageId,
1127
+ streaming: ctx.streaming,
1128
+ remarkPlugins,
1129
+ rehypePlugins,
1130
+ components
1013
1131
  },
1014
- defaultVariants: { active: false }
1132
+ ctx.messageId
1133
+ );
1134
+ return MarkdownRenderer;
1135
+ }
1136
+ var transformUrl = (url, key, node) => {
1137
+ if (key === "src" && node.tagName === "img" && (/^data:image\//i.test(url) || /^blob:/i.test(url))) {
1138
+ return url;
1015
1139
  }
1016
- );
1140
+ return defaultUrlTransform(url);
1141
+ };
1142
+ var MarkdownContent = React3.memo(function MarkdownContent2({
1143
+ text,
1144
+ messageId,
1145
+ streaming,
1146
+ remarkPlugins,
1147
+ rehypePlugins,
1148
+ components
1149
+ }) {
1150
+ return /* @__PURE__ */ jsx(TextRenderContext.Provider, { value: { messageId, streaming }, children: /* @__PURE__ */ jsx(
1151
+ Markdown,
1152
+ {
1153
+ remarkPlugins,
1154
+ rehypePlugins,
1155
+ urlTransform: transformUrl,
1156
+ components,
1157
+ children: text
1158
+ }
1159
+ ) });
1160
+ });
1017
1161
  function VirtualThread({
1018
1162
  items,
1019
1163
  participantById,
@@ -1024,32 +1168,28 @@ function VirtualThread({
1024
1168
  editable,
1025
1169
  onMessageEdited,
1026
1170
  defaultCopyFormat,
1027
- order,
1028
- conversationId,
1171
+ onOpenMedia,
1172
+ openMediaLabel,
1173
+ playMediaLabel,
1174
+ mediaErrorLabel,
1175
+ mediaRetryLabel,
1176
+ scrollRef,
1177
+ contentRef,
1029
1178
  containerProps
1030
1179
  }) {
1031
- const parentRef = React2.useRef(null);
1032
1180
  const virtualizer = useVirtualizer({
1033
1181
  count: items.length,
1034
- getScrollElement: () => parentRef.current,
1182
+ getScrollElement: () => scrollRef.current,
1035
1183
  // Rough first guess; real heights are measured via measureElement.
1036
1184
  estimateSize: () => 88,
1037
1185
  overscan: 10,
1038
1186
  getItemKey: (index) => items[index]?.id ?? index
1039
1187
  });
1040
- const count = items.length;
1041
- React2.useEffect(() => {
1042
- if (count === 0) return;
1043
- if (order === "desc") {
1044
- virtualizer.scrollToIndex(0, { align: "start" });
1045
- } else {
1046
- virtualizer.scrollToIndex(count - 1, { align: "end" });
1047
- }
1048
- }, [count, conversationId, order]);
1049
1188
  const virtualItems = virtualizer.getVirtualItems();
1050
- return /* @__PURE__ */ jsx("div", { ...containerProps, ref: parentRef, children: /* @__PURE__ */ jsx(
1189
+ return /* @__PURE__ */ jsx("div", { ...containerProps, ref: scrollRef, children: /* @__PURE__ */ jsx(
1051
1190
  "div",
1052
1191
  {
1192
+ ref: contentRef,
1053
1193
  style: {
1054
1194
  height: virtualizer.getTotalSize(),
1055
1195
  position: "relative",
@@ -1081,7 +1221,12 @@ function VirtualThread({
1081
1221
  onReferenceClick,
1082
1222
  editable,
1083
1223
  onMessageEdited,
1084
- defaultCopyFormat
1224
+ defaultCopyFormat,
1225
+ onOpenMedia,
1226
+ openMediaLabel,
1227
+ playMediaLabel,
1228
+ mediaErrorLabel,
1229
+ mediaRetryLabel
1085
1230
  }
1086
1231
  ) })
1087
1232
  },
@@ -1093,6 +1238,11 @@ function VirtualThread({
1093
1238
  }
1094
1239
  function SuperChat({
1095
1240
  conversation,
1241
+ view,
1242
+ defaultView = "thread",
1243
+ onViewChange,
1244
+ mediaFeedProps,
1245
+ mediaLabels,
1096
1246
  currentParticipantId,
1097
1247
  renderPlugins,
1098
1248
  renderTextContent,
@@ -1110,38 +1260,349 @@ function SuperChat({
1110
1260
  onReferenceClick,
1111
1261
  onBack
1112
1262
  }) {
1113
- const headingId = React2.useId();
1114
- React2.useEffect(() => {
1263
+ const headingId = React3.useId();
1264
+ const [internalView, setInternalView] = React3.useState({
1265
+ conversationId: conversation.id,
1266
+ view: defaultView
1267
+ });
1268
+ const activeView = view ?? (internalView.conversationId === conversation.id ? internalView.view : "thread");
1269
+ const labels = {
1270
+ backToConversation: "Back to conversation",
1271
+ openMedia: "Open in media feed",
1272
+ playMedia: "Play",
1273
+ unknownAuthor: "Unknown",
1274
+ ...mediaLabels
1275
+ };
1276
+ const mediaItems = React3.useMemo(() => {
1277
+ const items = getConversationMediaItems(conversation);
1278
+ return order === "desc" ? items.reverse() : items;
1279
+ }, [conversation, order]);
1280
+ const [mediaSelection, setMediaSelection] = React3.useState();
1281
+ const [manualPlaybackRequest, setManualPlaybackRequest] = React3.useState();
1282
+ const playbackRequestCounter = React3.useRef(0);
1283
+ const mediaFeedRef = React3.useRef(null);
1284
+ const backToConversationRef = React3.useRef(null);
1285
+ const focusMediaOnOpenRef = React3.useRef(false);
1286
+ const focusThreadOnBackRef = React3.useRef(false);
1287
+ const mediaReturnTargetRef = React3.useRef(void 0);
1288
+ const mediaContextRef = React3.useRef({
1289
+ conversation,
1290
+ view,
1291
+ onViewChange,
1292
+ mediaFeedProps,
1293
+ mediaItems
1294
+ });
1295
+ mediaContextRef.current = {
1296
+ conversation,
1297
+ view,
1298
+ onViewChange,
1299
+ mediaFeedProps,
1300
+ mediaItems
1301
+ };
1302
+ const setView = React3.useCallback((next) => {
1303
+ const context = mediaContextRef.current;
1304
+ if (context.view === void 0)
1305
+ setInternalView({ conversationId: context.conversation.id, view: next });
1306
+ context.onViewChange?.(next, { conversation: context.conversation });
1307
+ }, []);
1308
+ const handleMediaSelection = React3.useCallback((item) => {
1309
+ setMediaSelection({ conversationId: item.conversationId, itemId: item.id });
1310
+ mediaContextRef.current.mediaFeedProps?.onActiveItemChange?.(item);
1311
+ }, []);
1312
+ const handleOpenMedia = React3.useCallback(
1313
+ (messageId, attachmentId, play = false) => {
1314
+ const item = mediaContextRef.current.mediaItems.find(
1315
+ (candidate) => candidate.message.id === messageId && candidate.attachment.id === attachmentId
1316
+ );
1317
+ if (!item) return;
1318
+ handleMediaSelection(item);
1319
+ mediaReturnTargetRef.current = {
1320
+ conversationId: item.conversationId,
1321
+ messageId,
1322
+ attachmentId
1323
+ };
1324
+ focusMediaOnOpenRef.current = true;
1325
+ setManualPlaybackRequest(
1326
+ play ? {
1327
+ conversationId: item.conversationId,
1328
+ itemId: item.id,
1329
+ requestId: ++playbackRequestCounter.current
1330
+ } : void 0
1331
+ );
1332
+ setView("media");
1333
+ },
1334
+ [handleMediaSelection, setView]
1335
+ );
1336
+ const handleBackToConversation = React3.useCallback(() => {
1337
+ focusMediaOnOpenRef.current = false;
1338
+ focusThreadOnBackRef.current = true;
1339
+ setManualPlaybackRequest(void 0);
1340
+ setView("thread");
1341
+ }, [setView]);
1342
+ const hostPlaybackRequest = mediaFeedProps?.playbackRequest;
1343
+ const hostPlaybackKey = hostPlaybackRequest ? `${hostPlaybackRequest.itemId}\0${hostPlaybackRequest.requestId}` : void 0;
1344
+ React3.useEffect(() => {
1345
+ if (hostPlaybackKey === void 0) return;
1346
+ setManualPlaybackRequest(void 0);
1347
+ }, [hostPlaybackKey]);
1348
+ React3.useEffect(() => {
1349
+ if (internalView.conversationId !== conversation.id) {
1350
+ setInternalView({ conversationId: conversation.id, view: "thread" });
1351
+ }
1352
+ if (mediaReturnTargetRef.current?.conversationId !== conversation.id) {
1353
+ mediaReturnTargetRef.current = void 0;
1354
+ focusMediaOnOpenRef.current = false;
1355
+ focusThreadOnBackRef.current = false;
1356
+ setManualPlaybackRequest(void 0);
1357
+ }
1358
+ }, [conversation.id, internalView.conversationId]);
1359
+ React3.useEffect(() => {
1360
+ if (activeView !== "media" || !focusMediaOnOpenRef.current) return;
1361
+ const target = mediaFeedRef.current?.querySelector(
1362
+ 'article[tabindex="0"]'
1363
+ ) ?? mediaFeedRef.current?.querySelector('[role="feed"]');
1364
+ if (target) focusMediaOnOpenRef.current = false;
1365
+ (target ?? backToConversationRef.current)?.focus({ preventScroll: true });
1366
+ }, [
1367
+ activeView,
1368
+ mediaFeedProps?.loading,
1369
+ mediaFeedProps?.error,
1370
+ mediaItems.length
1371
+ ]);
1372
+ React3.useEffect(() => {
1115
1373
  notifyComposerMigrationOnce("SuperChat");
1116
1374
  }, []);
1117
- const renderText = React2.useMemo(
1375
+ const renderText = React3.useMemo(
1118
1376
  () => renderTextContent ?? createMarkdownRenderer({
1119
1377
  plugins: renderPlugins,
1120
1378
  trusted: trustedContent
1121
1379
  }),
1122
1380
  [renderTextContent, renderPlugins, trustedContent]
1123
1381
  );
1124
- const threadRef = React2.useRef(null);
1125
- React2.useEffect(() => {
1126
- if (virtualized) return;
1127
- const el = threadRef.current;
1128
- if (!el) return;
1129
- el.scrollTop = order === "desc" ? 0 : el.scrollHeight;
1130
- }, [conversation.thread.length, conversation.id, order, virtualized]);
1131
- const participantById = React2.useMemo(() => {
1382
+ const prefersReducedMotion = usePrefersReducedMotion();
1383
+ const {
1384
+ containerRef: threadRef,
1385
+ contentRef: threadContentRef,
1386
+ isAtBottom,
1387
+ scrollToBottom,
1388
+ anchorToTurnStart,
1389
+ followIfPinned,
1390
+ stopFollowing
1391
+ } = useStickToBottom({
1392
+ disabled: order === "desc" || activeView === "media"
1393
+ });
1394
+ React3.useEffect(() => {
1395
+ if (activeView !== "thread") return;
1396
+ setManualPlaybackRequest(void 0);
1397
+ if (!focusThreadOnBackRef.current) return;
1398
+ focusThreadOnBackRef.current = false;
1399
+ const source = mediaReturnTargetRef.current;
1400
+ const launchId = source ? JSON.stringify([source.messageId, source.attachmentId]) : void 0;
1401
+ const launcher = source?.conversationId === conversation.id ? Array.from(
1402
+ threadRef.current?.querySelectorAll(
1403
+ "[data-media-launch-id]"
1404
+ ) ?? []
1405
+ ).find((button) => button.dataset.mediaLaunchId === launchId) : void 0;
1406
+ (launcher ?? threadRef.current)?.focus({ preventScroll: true });
1407
+ }, [activeView, conversation.id, threadRef]);
1408
+ const [hasNewBelow, setHasNewBelow] = React3.useState(false);
1409
+ const [turnStartId, setTurnStartId] = React3.useState(null);
1410
+ const [turnMinHeight, setTurnMinHeight] = React3.useState();
1411
+ const anchoredTurnRef = React3.useRef(null);
1412
+ const threadSnapshotRef = React3.useRef(void 0);
1413
+ const atBottomRef = React3.useRef(isAtBottom);
1414
+ atBottomRef.current = isAtBottom;
1415
+ const pendingMediaOwnSendRef = React3.useRef(false);
1416
+ const pendingMediaAppendRef = React3.useRef(false);
1417
+ React3.useEffect(() => {
1418
+ threadSnapshotRef.current = void 0;
1419
+ pendingMediaOwnSendRef.current = false;
1420
+ pendingMediaAppendRef.current = false;
1421
+ setTurnStartId(null);
1422
+ anchoredTurnRef.current = null;
1423
+ if (order === "desc") {
1424
+ const el = threadRef.current;
1425
+ if (el) el.scrollTop = 0;
1426
+ } else {
1427
+ scrollToBottom("auto");
1428
+ }
1429
+ setHasNewBelow(false);
1430
+ }, [conversation.id, order]);
1431
+ const threadLength = conversation.thread.length;
1432
+ const prevThreadLengthRef = React3.useRef(threadLength);
1433
+ const prevMessageIdsRef = React3.useRef(
1434
+ new Set(conversation.thread.map((message) => message.id))
1435
+ );
1436
+ const policyConversationRef = React3.useRef(conversation.id);
1437
+ const policyBaselinedRef = React3.useRef(false);
1438
+ React3.useEffect(() => {
1439
+ if (!policyBaselinedRef.current || policyConversationRef.current !== conversation.id) {
1440
+ policyBaselinedRef.current = true;
1441
+ policyConversationRef.current = conversation.id;
1442
+ prevThreadLengthRef.current = threadLength;
1443
+ prevMessageIdsRef.current = new Set(
1444
+ conversation.thread.map((message) => message.id)
1445
+ );
1446
+ if (order !== "desc" && [...conversation.thread].sort(byTime).at(-1)?.status === "streaming") {
1447
+ stopFollowing();
1448
+ }
1449
+ return;
1450
+ }
1451
+ if (threadLength === prevThreadLengthRef.current) return;
1452
+ const grew = threadLength > prevThreadLengthRef.current;
1453
+ prevThreadLengthRef.current = threadLength;
1454
+ if (grew && activeView === "media") pendingMediaAppendRef.current = true;
1455
+ if (order === "desc") {
1456
+ const el = threadRef.current;
1457
+ if (el) el.scrollTop = 0;
1458
+ return;
1459
+ }
1460
+ const prevIds = prevMessageIdsRef.current;
1461
+ let turnStart;
1462
+ if (grew && currentParticipantId) {
1463
+ for (const message of [...conversation.thread].sort(byTime)) {
1464
+ if (!prevIds.has(message.id) && message.participantId === currentParticipantId) {
1465
+ turnStart = message.id;
1466
+ }
1467
+ }
1468
+ }
1469
+ if (turnStart) {
1470
+ if (activeView === "media") pendingMediaOwnSendRef.current = true;
1471
+ if (virtualized) {
1472
+ scrollToBottom("auto");
1473
+ } else {
1474
+ setTurnStartId(turnStart);
1475
+ }
1476
+ } else if (grew) {
1477
+ const newest = [...conversation.thread].sort(byTime).at(-1);
1478
+ if (newest?.status === "streaming") {
1479
+ followIfPinned("auto");
1480
+ stopFollowing();
1481
+ } else if (!followIfPinned("auto")) {
1482
+ setHasNewBelow(true);
1483
+ }
1484
+ } else {
1485
+ followIfPinned("auto");
1486
+ }
1487
+ }, [threadLength, order, isAtBottom, conversation.id, activeView]);
1488
+ React3.useLayoutEffect(() => {
1489
+ if (activeView !== "thread") return;
1490
+ const container = threadRef.current;
1491
+ if (!container) return;
1492
+ const snapshot = threadSnapshotRef.current;
1493
+ const sameThread = snapshot?.conversationId === conversation.id && snapshot.order === order;
1494
+ const ownSend = pendingMediaOwnSendRef.current;
1495
+ const appended = pendingMediaAppendRef.current;
1496
+ pendingMediaOwnSendRef.current = false;
1497
+ pendingMediaAppendRef.current = false;
1498
+ if (order === "desc") {
1499
+ container.scrollTop = sameThread && !appended ? snapshot.scrollTop : 0;
1500
+ } else if (ownSend && !virtualized) ; else if (sameThread && !ownSend && (!snapshot.atBottom || !appended)) {
1501
+ container.scrollTop = snapshot.scrollTop;
1502
+ if (!snapshot.atBottom) stopFollowing();
1503
+ } else {
1504
+ scrollToBottom("auto");
1505
+ if ([...conversation.thread].sort(byTime).at(-1)?.status === "streaming")
1506
+ stopFollowing();
1507
+ }
1508
+ return () => {
1509
+ threadSnapshotRef.current = {
1510
+ conversationId: conversation.id,
1511
+ order,
1512
+ scrollTop: container.scrollTop,
1513
+ atBottom: atBottomRef.current
1514
+ };
1515
+ };
1516
+ }, [conversation.id, order, activeView, virtualized]);
1517
+ React3.useLayoutEffect(() => {
1518
+ if (!turnStartId || anchoredTurnRef.current === turnStartId) return;
1519
+ const container = threadRef.current;
1520
+ if (!container) return;
1521
+ const reserve = Math.max(0, container.clientHeight - 32);
1522
+ if (turnMinHeight !== reserve) {
1523
+ setTurnMinHeight(reserve);
1524
+ return;
1525
+ }
1526
+ const target = container.querySelector(
1527
+ '[data-slot="superchat-turn"]'
1528
+ );
1529
+ if (target) {
1530
+ anchorToTurnStart(target, prefersReducedMotion ? "auto" : "smooth");
1531
+ anchoredTurnRef.current = turnStartId;
1532
+ }
1533
+ }, [
1534
+ turnStartId,
1535
+ turnMinHeight,
1536
+ anchorToTurnStart,
1537
+ prefersReducedMotion,
1538
+ threadRef,
1539
+ activeView
1540
+ ]);
1541
+ React3.useEffect(() => {
1542
+ prevMessageIdsRef.current = new Set(
1543
+ conversation.thread.map((message) => message.id)
1544
+ );
1545
+ });
1546
+ React3.useEffect(() => {
1547
+ if (isAtBottom) setHasNewBelow(false);
1548
+ }, [isAtBottom]);
1549
+ const newestMessage = React3.useMemo(
1550
+ () => [...conversation.thread].sort(byTime).at(-1),
1551
+ [conversation]
1552
+ );
1553
+ const raiseNewBelow = React3.useCallback(() => {
1554
+ if (order !== "desc") setHasNewBelow(true);
1555
+ }, [order]);
1556
+ const resumeFollowing = React3.useCallback(() => {
1557
+ if (order !== "desc") scrollToBottom("auto");
1558
+ }, [order, scrollToBottom]);
1559
+ useStreamEndedBelowFold(
1560
+ newestMessage,
1561
+ isAtBottom,
1562
+ raiseNewBelow,
1563
+ resumeFollowing
1564
+ );
1565
+ const handleJumpToBottom = React3.useCallback(() => {
1566
+ scrollToBottom(prefersReducedMotion ? "auto" : "smooth");
1567
+ }, [scrollToBottom, prefersReducedMotion]);
1568
+ const participantById = React3.useMemo(() => {
1132
1569
  const map = /* @__PURE__ */ new Map();
1133
1570
  conversation.participants.forEach((p) => map.set(p.id, p));
1134
1571
  return map;
1135
1572
  }, [conversation]);
1136
- const orderedThread = React2.useMemo(() => {
1573
+ const orderedThread = React3.useMemo(() => {
1137
1574
  const sorted = [...conversation.thread].sort(byTime);
1138
1575
  return order === "desc" ? sorted.reverse() : sorted;
1139
1576
  }, [conversation, order]);
1140
- const onMessageEditedRef = React2.useRef(onMessageEdited);
1577
+ const turnIndex = React3.useMemo(
1578
+ () => turnStartId && order !== "desc" ? orderedThread.findIndex((message) => message.id === turnStartId) : -1,
1579
+ [orderedThread, turnStartId, order]
1580
+ );
1581
+ const renderMessageRow = (m) => /* @__PURE__ */ jsx(
1582
+ MessageRow,
1583
+ {
1584
+ message: m,
1585
+ participant: participantById.get(m.participantId),
1586
+ isSelf: !!currentParticipantId && m.participantId === currentParticipantId,
1587
+ renderText,
1588
+ linkBuilder,
1589
+ onReferenceClick,
1590
+ editable,
1591
+ onMessageEdited: handleMessageEdited,
1592
+ defaultCopyFormat,
1593
+ onOpenMedia: handleOpenMedia,
1594
+ openMediaLabel: labels.openMedia,
1595
+ playMediaLabel: labels.playMedia,
1596
+ mediaErrorLabel: mediaFeedProps?.labels?.mediaError,
1597
+ mediaRetryLabel: mediaFeedProps?.labels?.retry
1598
+ },
1599
+ m.id
1600
+ );
1601
+ const onMessageEditedRef = React3.useRef(onMessageEdited);
1141
1602
  onMessageEditedRef.current = onMessageEdited;
1142
- const conversationRef = React2.useRef(conversation);
1603
+ const conversationRef = React3.useRef(conversation);
1143
1604
  conversationRef.current = conversation;
1144
- const handleMessageEdited = React2.useCallback(
1605
+ const handleMessageEdited = React3.useCallback(
1145
1606
  (messageId, text) => {
1146
1607
  onMessageEditedRef.current?.(messageId, text, {
1147
1608
  conversation: conversationRef.current
@@ -1150,7 +1611,7 @@ function SuperChat({
1150
1611
  []
1151
1612
  );
1152
1613
  const editable = !readOnly && !!onMessageEdited;
1153
- const mentionOptions = React2.useMemo(
1614
+ const mentionOptions = React3.useMemo(
1154
1615
  () => conversation.participants.filter((p) => p.kind !== "system").map((p) => ({
1155
1616
  id: p.id,
1156
1617
  label: p.name,
@@ -1160,17 +1621,17 @@ function SuperChat({
1160
1621
  })),
1161
1622
  [conversation.participants]
1162
1623
  );
1163
- const composerAccept = React2.useMemo(
1624
+ const composerAccept = React3.useMemo(
1164
1625
  () => acceptTokensFor(acceptedFileTypes),
1165
1626
  [acceptedFileTypes]
1166
1627
  );
1167
- const [draft, setDraft] = React2.useState("");
1168
- const draftEpochRef = React2.useRef(0);
1169
- const handleDraftChange = React2.useCallback((value) => {
1628
+ const [draft, setDraft] = React3.useState("");
1629
+ const draftEpochRef = React3.useRef(0);
1630
+ const handleDraftChange = React3.useCallback((value) => {
1170
1631
  draftEpochRef.current += 1;
1171
1632
  setDraft(value);
1172
1633
  }, []);
1173
- const handleComposerSend = React2.useCallback(
1634
+ const handleComposerSend = React3.useCallback(
1174
1635
  async (message) => {
1175
1636
  const epoch = draftEpochRef.current;
1176
1637
  try {
@@ -1266,55 +1727,129 @@ function SuperChat({
1266
1727
  ]
1267
1728
  }
1268
1729
  ),
1269
- virtualized ? /* @__PURE__ */ jsx(
1270
- VirtualThread,
1730
+ activeView === "media" ? /* @__PURE__ */ jsxs(
1731
+ "div",
1271
1732
  {
1272
- items: orderedThread,
1273
- participantById,
1274
- currentParticipantId,
1275
- renderText,
1276
- linkBuilder,
1277
- onReferenceClick,
1278
- editable,
1279
- onMessageEdited: handleMessageEdited,
1280
- defaultCopyFormat,
1281
- order,
1282
- conversationId: conversation.id,
1283
- containerProps: {
1284
- "data-slot": "superchat-thread",
1285
- role: "log",
1286
- "aria-label": "Messages",
1287
- "aria-live": "polite",
1288
- // Focusable so keyboard-only users can scroll the message history.
1289
- tabIndex: 0,
1290
- className: "flex-1 overflow-y-auto p-4"
1291
- }
1733
+ "data-slot": "superchat-media-view",
1734
+ className: "flex min-h-0 flex-1 flex-col",
1735
+ children: [
1736
+ /* @__PURE__ */ jsx("div", { className: "px-4 pt-2", children: /* @__PURE__ */ jsx(ButtonGroup, { className: "justify-start", children: /* @__PURE__ */ jsx(
1737
+ Button,
1738
+ {
1739
+ ref: backToConversationRef,
1740
+ variant: "ghost",
1741
+ size: "sm",
1742
+ leftIcon: /* @__PURE__ */ jsx(
1743
+ ArrowLeft,
1744
+ {
1745
+ className: "size-4 rtl:rotate-180",
1746
+ "aria-hidden": "true"
1747
+ }
1748
+ ),
1749
+ onClick: handleBackToConversation,
1750
+ children: labels.backToConversation
1751
+ }
1752
+ ) }) }),
1753
+ /* @__PURE__ */ createElement(
1754
+ MediaFeed,
1755
+ {
1756
+ ...mediaFeedProps,
1757
+ ref: mediaFeedRef,
1758
+ key: conversation.id,
1759
+ items: mediaItems,
1760
+ getId: (item) => item.id,
1761
+ getMedia: (item) => item.attachment,
1762
+ getTitle: (item) => item.attachment.title ?? "",
1763
+ getCaption: (item) => item.attachment.caption ?? item.message.text,
1764
+ getAuthor: (item) => ({
1765
+ name: item.participant?.name ?? labels.unknownAuthor,
1766
+ avatar: item.participant?.avatar
1767
+ }),
1768
+ activeItemId: mediaFeedProps?.activeItemId ?? (mediaSelection?.conversationId === conversation.id ? mediaSelection.itemId : void 0),
1769
+ onActiveItemChange: handleMediaSelection,
1770
+ playbackRequest: manualPlaybackRequest?.conversationId === conversation.id ? manualPlaybackRequest : mediaFeedProps?.playbackRequest,
1771
+ className: cn("min-h-0 flex-1", mediaFeedProps?.className)
1772
+ }
1773
+ )
1774
+ ]
1292
1775
  }
1293
- ) : /* @__PURE__ */ jsx(
1776
+ ) : /* @__PURE__ */ jsxs(
1294
1777
  "div",
1295
1778
  {
1296
- "data-slot": "superchat-thread",
1297
- ref: threadRef,
1298
- role: "log",
1299
- "aria-label": "Messages",
1300
- "aria-live": "polite",
1301
- tabIndex: 0,
1302
- className: "flex-1 space-y-4 overflow-y-auto p-4",
1303
- children: orderedThread.map((m) => /* @__PURE__ */ jsx(
1304
- MessageRow,
1305
- {
1306
- message: m,
1307
- participant: participantById.get(m.participantId),
1308
- isSelf: !!currentParticipantId && m.participantId === currentParticipantId,
1309
- renderText,
1310
- linkBuilder,
1311
- onReferenceClick,
1312
- editable,
1313
- onMessageEdited: handleMessageEdited,
1314
- defaultCopyFormat
1315
- },
1316
- m.id
1317
- ))
1779
+ "data-slot": "superchat-thread-viewport",
1780
+ className: "relative flex min-h-0 flex-1 flex-col",
1781
+ children: [
1782
+ virtualized ? /* @__PURE__ */ jsx(
1783
+ VirtualThread,
1784
+ {
1785
+ items: orderedThread,
1786
+ participantById,
1787
+ currentParticipantId,
1788
+ renderText,
1789
+ linkBuilder,
1790
+ onReferenceClick,
1791
+ editable,
1792
+ onMessageEdited: handleMessageEdited,
1793
+ defaultCopyFormat,
1794
+ onOpenMedia: handleOpenMedia,
1795
+ openMediaLabel: labels.openMedia,
1796
+ playMediaLabel: labels.playMedia,
1797
+ mediaErrorLabel: mediaFeedProps?.labels?.mediaError,
1798
+ mediaRetryLabel: mediaFeedProps?.labels?.retry,
1799
+ scrollRef: threadRef,
1800
+ contentRef: threadContentRef,
1801
+ containerProps: {
1802
+ "data-slot": "superchat-thread",
1803
+ role: "log",
1804
+ "aria-label": "Messages",
1805
+ "aria-live": "polite",
1806
+ // Focusable so keyboard-only users can scroll the message history.
1807
+ tabIndex: 0,
1808
+ className: "flex-1 overflow-y-auto p-4"
1809
+ }
1810
+ }
1811
+ ) : /* @__PURE__ */ jsx(
1812
+ "div",
1813
+ {
1814
+ "data-slot": "superchat-thread",
1815
+ ref: threadRef,
1816
+ role: "log",
1817
+ "aria-label": "Messages",
1818
+ "aria-live": "polite",
1819
+ tabIndex: 0,
1820
+ className: "flex-1 overflow-y-auto p-4",
1821
+ children: /* @__PURE__ */ jsxs("div", { ref: threadContentRef, className: "space-y-4", children: [
1822
+ (turnIndex === -1 ? orderedThread : orderedThread.slice(0, turnIndex)).map(renderMessageRow),
1823
+ turnIndex !== -1 && /* @__PURE__ */ jsx(
1824
+ "div",
1825
+ {
1826
+ "data-slot": "superchat-turn",
1827
+ className: "space-y-4",
1828
+ style: { minHeight: turnMinHeight },
1829
+ children: orderedThread.slice(turnIndex).map(renderMessageRow)
1830
+ }
1831
+ )
1832
+ ] })
1833
+ }
1834
+ ),
1835
+ /* @__PURE__ */ jsx(AnimatedPresence, { children: order !== "desc" && !isAtBottom && /* @__PURE__ */ jsx(
1836
+ Animated,
1837
+ {
1838
+ preset: "fade",
1839
+ mode: "presence",
1840
+ className: "absolute inset-x-0 bottom-0 z-20",
1841
+ children: /* @__PURE__ */ jsx(
1842
+ JumpToBottomButton,
1843
+ {
1844
+ dataSlot: "superchat-jump-to-bottom",
1845
+ hasNewMessages: hasNewBelow,
1846
+ onClick: handleJumpToBottom
1847
+ }
1848
+ )
1849
+ },
1850
+ "jump-to-bottom"
1851
+ ) })
1852
+ ]
1318
1853
  }
1319
1854
  ),
1320
1855
  /* @__PURE__ */ jsx(
@@ -1324,6 +1859,7 @@ function SuperChat({
1324
1859
  onValueChange: handleDraftChange,
1325
1860
  onSend: handleComposerSend,
1326
1861
  disabled: readOnly,
1862
+ className: "px-4 pb-4",
1327
1863
  placeholder: readOnly ? "Read-only conversation" : "Type a message\u2026 use @ to address an agent",
1328
1864
  mentionOptions,
1329
1865
  allowAttachments: !readOnly,
@@ -1345,12 +1881,14 @@ function SuperChatConversations({
1345
1881
  onConversationOpened,
1346
1882
  onNewConversation
1347
1883
  }) {
1348
- const [internalActive, setInternalActive] = React2.useState(
1884
+ const [internalActive, setInternalActive] = React3.useState(
1349
1885
  defaultActiveConversationId ?? conversations[0]?.id
1350
1886
  );
1887
+ const [hasMounted, setHasMounted] = React3.useState(false);
1888
+ React3.useEffect(() => setHasMounted(true), []);
1351
1889
  const requestedId = activeConversationId ?? internalActive;
1352
1890
  const activeId = conversations.some((c) => c.id === requestedId) ? requestedId : conversations[0]?.id;
1353
- const sortedConversations = React2.useMemo(
1891
+ const sortedConversations = React3.useMemo(
1354
1892
  () => [...conversations].sort((a, b) => lastActivityOf(b) - lastActivityOf(a)),
1355
1893
  [conversations]
1356
1894
  );
@@ -1402,10 +1940,21 @@ function SuperChatConversations({
1402
1940
  /* @__PURE__ */ jsx("span", { className: "block truncate font-medium", children: c.title }),
1403
1941
  last?.text && /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-neutral-600 dark:text-neutral-400", children: last.text })
1404
1942
  ] }),
1405
- !!c.unread && /* @__PURE__ */ jsxs("span", { className: "bg-primary-600 ms-1 inline-flex h-5 min-w-5 items-center justify-center rounded-full px-1.5 text-[10px] font-semibold text-white", children: [
1406
- c.unread,
1407
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: " unread messages" })
1408
- ] })
1943
+ /* @__PURE__ */ jsx(AnimatedPresence, { initial: hasMounted, children: !!c.unread && /* @__PURE__ */ jsxs(
1944
+ Animated,
1945
+ {
1946
+ as: "span",
1947
+ preset: "pop",
1948
+ mode: "presence",
1949
+ "data-slot": "superchat-unread-badge",
1950
+ className: "bg-primary-600 ms-1 inline-flex h-5 min-w-5 items-center justify-center rounded-full px-1.5 text-[10px] font-semibold text-white",
1951
+ children: [
1952
+ c.unread,
1953
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: " unread messages" })
1954
+ ]
1955
+ },
1956
+ "unread"
1957
+ ) })
1409
1958
  ]
1410
1959
  }
1411
1960
  ) }, c.id);
@@ -1418,6 +1967,11 @@ function SuperChatConversations({
1418
1967
  }
1419
1968
  function SuperChatInbox({
1420
1969
  conversations,
1970
+ view,
1971
+ defaultView,
1972
+ onViewChange,
1973
+ mediaFeedProps,
1974
+ mediaLabels,
1421
1975
  activeConversationId,
1422
1976
  defaultActiveConversationId,
1423
1977
  currentParticipantId,
@@ -1439,13 +1993,13 @@ function SuperChatInbox({
1439
1993
  onNewConversation,
1440
1994
  onReferenceClick
1441
1995
  }) {
1442
- const [internalActive, setInternalActive] = React2.useState(
1996
+ const [internalActive, setInternalActive] = React3.useState(
1443
1997
  defaultActiveConversationId ?? conversations[0]?.id
1444
1998
  );
1445
1999
  const requestedId = activeConversationId ?? internalActive;
1446
2000
  const active = conversations.find((c) => c.id === requestedId) ?? conversations[0];
1447
2001
  const activeId = active?.id;
1448
- const [mobileView, setMobileView] = React2.useState("list");
2002
+ const [mobileView, setMobileView] = React3.useState("list");
1449
2003
  const handleOpen = (c) => {
1450
2004
  if (activeConversationId === void 0) setInternalActive(c.id);
1451
2005
  setMobileView("chat");
@@ -1479,6 +2033,11 @@ function SuperChatInbox({
1479
2033
  SuperChat,
1480
2034
  {
1481
2035
  conversation: active,
2036
+ view,
2037
+ defaultView,
2038
+ onViewChange,
2039
+ mediaFeedProps,
2040
+ mediaLabels,
1482
2041
  currentParticipantId,
1483
2042
  renderPlugins,
1484
2043
  renderTextContent,
@@ -1514,6 +2073,6 @@ function SuperChatInbox({
1514
2073
  );
1515
2074
  }
1516
2075
 
1517
- export { SuperChat, SuperChatConversations, SuperChatInbox, createMarkdownRenderer };
2076
+ export { SuperChat, SuperChatConversations, SuperChatInbox, createMarkdownRenderer, getConversationMediaItems };
1518
2077
  //# sourceMappingURL=index.js.map
1519
2078
  //# sourceMappingURL=index.js.map