@dxos/plugin-thread 0.8.3 → 0.8.4-main.c1de068

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 (247) hide show
  1. package/dist/lib/browser/ChannelContainer-IY2UIRLF.mjs +16 -0
  2. package/dist/lib/browser/ChatContainer-AIGIWAUG.mjs +15 -0
  3. package/dist/lib/browser/{app-graph-builder-OY7R7EJP.mjs → app-graph-builder-N7BE5TYW.mjs} +6 -6
  4. package/dist/lib/browser/{call-manager-APQAZWHT.mjs → call-manager-NIPDYUVD.mjs} +6 -5
  5. package/dist/lib/browser/chunk-4OYAYON2.mjs +21 -0
  6. package/dist/lib/browser/chunk-6NSMBO3B.mjs +56 -0
  7. package/dist/lib/browser/chunk-6NSMBO3B.mjs.map +7 -0
  8. package/dist/lib/browser/{chunk-5P5BH5GE.mjs → chunk-ERWASUQK.mjs} +66 -5
  9. package/dist/lib/browser/chunk-ERWASUQK.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-IIUTBDVB.mjs → chunk-EV4JWI7L.mjs} +2 -2
  11. package/dist/lib/browser/{chunk-AEXWNS6Z.mjs → chunk-GCLD5ESP.mjs} +14 -5
  12. package/dist/lib/browser/chunk-GCLD5ESP.mjs.map +7 -0
  13. package/dist/lib/browser/{chunk-JKQUJOTX.mjs → chunk-GERVMFQW.mjs} +2 -2
  14. package/dist/lib/browser/{chunk-XZKBN3NS.mjs → chunk-KWPRNHTK.mjs} +32 -31
  15. package/dist/lib/browser/chunk-KWPRNHTK.mjs.map +7 -0
  16. package/dist/lib/browser/{chunk-R5MDLUPC.mjs → chunk-LGSDKXPF.mjs} +3 -3
  17. package/dist/lib/browser/chunk-VUWC4IJM.mjs +479 -0
  18. package/dist/lib/browser/chunk-VUWC4IJM.mjs.map +7 -0
  19. package/dist/lib/browser/chunk-XLPJXUKO.mjs +367 -0
  20. package/dist/lib/browser/chunk-XLPJXUKO.mjs.map +7 -0
  21. package/dist/lib/browser/{chunk-4H4A264L.mjs → chunk-ZE7KWN36.mjs} +85 -124
  22. package/dist/lib/browser/chunk-ZE7KWN36.mjs.map +7 -0
  23. package/dist/lib/browser/index.mjs +35 -41
  24. package/dist/lib/browser/index.mjs.map +3 -3
  25. package/dist/lib/browser/{intent-resolver-FK2MDVDT.mjs → intent-resolver-JFGLZ6VI.mjs} +30 -14
  26. package/dist/lib/browser/intent-resolver-JFGLZ6VI.mjs.map +7 -0
  27. package/dist/lib/browser/{markdown-TE5SWWNJ.mjs → markdown-GEXBVJYN.mjs} +7 -7
  28. package/dist/lib/browser/meta.json +1 -1
  29. package/dist/lib/browser/react-root-X4UIVGTX.mjs +28 -0
  30. package/dist/lib/browser/{react-surface-VXUJKSOG.mjs → react-surface-YCYEFBPM.mjs} +12 -11
  31. package/dist/lib/browser/{settings-RB2RSLXV.mjs → settings-E32MTL7A.mjs} +4 -4
  32. package/dist/lib/browser/{state-RKL5MSDP.mjs → state-H6CYONWE.mjs} +4 -4
  33. package/dist/lib/browser/types/index.mjs +2 -2
  34. package/dist/lib/node-esm/ChannelContainer-DET6T5N2.mjs +17 -0
  35. package/dist/lib/node-esm/{ChatContainer-F6CSADV7.mjs → ChatContainer-IQUWU426.mjs} +6 -5
  36. package/dist/lib/node-esm/{app-graph-builder-BAHBHYWI.mjs → app-graph-builder-VCW76Z6V.mjs} +6 -6
  37. package/dist/lib/node-esm/{call-manager-UUYXLF4T.mjs → call-manager-D6O5ZJJ4.mjs} +6 -5
  38. package/dist/lib/{browser/call-manager-APQAZWHT.mjs.map → node-esm/call-manager-D6O5ZJJ4.mjs.map} +1 -1
  39. package/dist/lib/node-esm/{chunk-O3V45YJP.mjs → chunk-25ABSYP2.mjs} +65 -5
  40. package/dist/lib/node-esm/chunk-25ABSYP2.mjs.map +7 -0
  41. package/dist/lib/node-esm/chunk-2MFNK53T.mjs +480 -0
  42. package/dist/lib/node-esm/chunk-2MFNK53T.mjs.map +7 -0
  43. package/dist/lib/node-esm/{chunk-PGRP3O4O.mjs → chunk-57XR3LEF.mjs} +2 -2
  44. package/dist/lib/node-esm/{chunk-K4KAUOKT.mjs → chunk-75RJ5DJI.mjs} +3 -3
  45. package/dist/lib/node-esm/{chunk-2RNIPFDA.mjs → chunk-C3XFMUAY.mjs} +32 -31
  46. package/dist/lib/node-esm/chunk-C3XFMUAY.mjs.map +7 -0
  47. package/dist/lib/node-esm/{chunk-ESQC6SYE.mjs → chunk-GRLRWTRU.mjs} +2 -2
  48. package/dist/lib/node-esm/chunk-GW37AAM4.mjs +23 -0
  49. package/dist/lib/node-esm/{chunk-WXNPD542.mjs → chunk-IHDNQLLR.mjs} +84 -124
  50. package/dist/lib/node-esm/chunk-IHDNQLLR.mjs.map +7 -0
  51. package/dist/lib/node-esm/chunk-J4NSON5Q.mjs +368 -0
  52. package/dist/lib/node-esm/chunk-J4NSON5Q.mjs.map +7 -0
  53. package/dist/lib/node-esm/chunk-OU5BYIDO.mjs +58 -0
  54. package/dist/lib/node-esm/chunk-OU5BYIDO.mjs.map +7 -0
  55. package/dist/lib/node-esm/{chunk-UJMPYKT3.mjs → chunk-TDFHTCZZ.mjs} +14 -5
  56. package/dist/lib/node-esm/chunk-TDFHTCZZ.mjs.map +7 -0
  57. package/dist/lib/node-esm/index.mjs +35 -41
  58. package/dist/lib/node-esm/index.mjs.map +3 -3
  59. package/dist/lib/node-esm/{intent-resolver-BU73VYW3.mjs → intent-resolver-OXGNQ44Y.mjs} +30 -14
  60. package/dist/lib/node-esm/intent-resolver-OXGNQ44Y.mjs.map +7 -0
  61. package/dist/lib/node-esm/{markdown-HJUWNBLS.mjs → markdown-LIJZDK2J.mjs} +7 -7
  62. package/dist/lib/node-esm/meta.json +1 -1
  63. package/dist/lib/node-esm/{react-root-RUXOAQNW.mjs → react-root-M7J6PZVW.mjs} +12 -11
  64. package/dist/lib/{browser/react-root-NK3A4VG7.mjs.map → node-esm/react-root-M7J6PZVW.mjs.map} +1 -1
  65. package/dist/lib/node-esm/{react-surface-ELXFYKP6.mjs → react-surface-IRSEKM42.mjs} +12 -11
  66. package/dist/lib/{browser/react-surface-VXUJKSOG.mjs.map → node-esm/react-surface-IRSEKM42.mjs.map} +1 -1
  67. package/dist/lib/node-esm/{settings-EA7DFSM6.mjs → settings-SJ24YG7M.mjs} +4 -4
  68. package/dist/lib/node-esm/{state-6AUTNROZ.mjs → state-D7WNDT3N.mjs} +4 -4
  69. package/dist/lib/node-esm/types/index.mjs +2 -2
  70. package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
  71. package/dist/types/src/calls/call-manager.d.ts +1 -1
  72. package/dist/types/src/calls/call-manager.d.ts.map +1 -1
  73. package/dist/types/src/calls/media-manager.d.ts.map +1 -1
  74. package/dist/types/src/calls/util/calls-service.d.ts +4 -1
  75. package/dist/types/src/calls/util/calls-service.d.ts.map +1 -1
  76. package/dist/types/src/calls/util/stub-media-streams.d.ts.map +1 -1
  77. package/dist/types/src/calls-service.stories.d.ts +22 -0
  78. package/dist/types/src/calls-service.stories.d.ts.map +1 -0
  79. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  80. package/dist/types/src/components/ChannelContainer.d.ts.map +1 -1
  81. package/dist/types/src/components/ChannelContainer.stories.d.ts +2 -2
  82. package/dist/types/src/components/ChannelContainer.stories.d.ts.map +1 -1
  83. package/dist/types/src/components/Chat.stories.d.ts +3 -2
  84. package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
  85. package/dist/types/src/components/ChatContainer.d.ts +2 -2
  86. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  87. package/dist/types/src/components/Comments.stories.d.ts +1 -1
  88. package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
  89. package/dist/types/src/components/CommentsContainer.d.ts +4 -4
  90. package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
  91. package/dist/types/src/components/CommentsThreadContainer.d.ts +14 -0
  92. package/dist/types/src/components/CommentsThreadContainer.d.ts.map +1 -0
  93. package/dist/types/src/components/Media/VideoObject.stories.d.ts +1 -1
  94. package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -1
  95. package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
  96. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +1 -1
  97. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +1 -1
  98. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +1 -1
  99. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +1 -1
  100. package/dist/types/src/components/index.d.ts +1 -1
  101. package/dist/types/src/components/index.d.ts.map +1 -1
  102. package/dist/types/src/hooks/index.d.ts +2 -0
  103. package/dist/types/src/hooks/index.d.ts.map +1 -1
  104. package/dist/types/src/hooks/useInaudibleAudioStreamTrack.d.ts +2 -0
  105. package/dist/types/src/hooks/useInaudibleAudioStreamTrack.d.ts.map +1 -0
  106. package/dist/types/src/hooks/useVideoStreamTrack.d.ts +3 -0
  107. package/dist/types/src/hooks/useVideoStreamTrack.d.ts.map +1 -0
  108. package/dist/types/src/testing/stories.d.ts.map +1 -1
  109. package/dist/types/src/translations.d.ts +74 -194
  110. package/dist/types/src/translations.d.ts.map +1 -1
  111. package/dist/types/src/types/schema.d.ts +50 -21
  112. package/dist/types/src/types/schema.d.ts.map +1 -1
  113. package/dist/types/src/types/types.d.ts +68 -22
  114. package/dist/types/src/types/types.d.ts.map +1 -1
  115. package/dist/types/src/util.d.ts +17 -2
  116. package/dist/types/src/util.d.ts.map +1 -1
  117. package/dist/types/tsconfig.tsbuildinfo +1 -1
  118. package/package.json +47 -48
  119. package/src/ThreadPlugin.tsx +7 -22
  120. package/src/calls/call-manager.ts +6 -2
  121. package/src/calls/media-manager.ts +11 -4
  122. package/src/calls/util/calls-service.ts +8 -5
  123. package/src/calls/util/stub-media-streams.ts +3 -6
  124. package/src/calls-service.stories.tsx +216 -0
  125. package/src/capabilities/intent-resolver.ts +22 -4
  126. package/src/components/Call/Call.tsx +1 -1
  127. package/src/components/Call/Toolbar.tsx +3 -3
  128. package/src/components/CallDebugPanel.tsx +2 -2
  129. package/src/components/ChannelContainer.stories.tsx +5 -5
  130. package/src/components/ChannelContainer.tsx +6 -5
  131. package/src/components/Chat.stories.tsx +4 -4
  132. package/src/components/ChatContainer.tsx +12 -11
  133. package/src/components/Comments.stories.tsx +22 -15
  134. package/src/components/CommentsContainer.tsx +16 -11
  135. package/src/components/{CommentContainer.tsx → CommentsThreadContainer.tsx} +49 -80
  136. package/src/components/Media/VideoObject.stories.tsx +1 -1
  137. package/src/components/MessageContainer.tsx +29 -45
  138. package/src/components/ResponsiveGrid/ResponsiveContainer.stories.tsx +2 -2
  139. package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +3 -3
  140. package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +2 -2
  141. package/src/components/ThreadComplementary.tsx +2 -2
  142. package/src/components/ThreadSettings.tsx +2 -2
  143. package/src/components/index.ts +1 -1
  144. package/src/components/testing.ts +2 -2
  145. package/src/hooks/index.ts +2 -0
  146. package/src/hooks/useInaudibleAudioStreamTrack.tsx +27 -0
  147. package/src/hooks/useVideoStreamTrack.tsx +33 -0
  148. package/src/testing/stories.ts +5 -1
  149. package/src/translations.ts +11 -8
  150. package/src/types/types.ts +9 -1
  151. package/dist/lib/browser/ChannelContainer-PKFBVENP.mjs +0 -15
  152. package/dist/lib/browser/ChatContainer-RSOKYAMK.mjs +0 -14
  153. package/dist/lib/browser/chunk-4H4A264L.mjs.map +0 -7
  154. package/dist/lib/browser/chunk-5P5BH5GE.mjs.map +0 -7
  155. package/dist/lib/browser/chunk-6NBVNXTM.mjs +0 -21
  156. package/dist/lib/browser/chunk-AEXWNS6Z.mjs.map +0 -7
  157. package/dist/lib/browser/chunk-PG5CTFKK.mjs +0 -550
  158. package/dist/lib/browser/chunk-PG5CTFKK.mjs.map +0 -7
  159. package/dist/lib/browser/chunk-TAFSCSUR.mjs +0 -351
  160. package/dist/lib/browser/chunk-TAFSCSUR.mjs.map +0 -7
  161. package/dist/lib/browser/chunk-XZKBN3NS.mjs.map +0 -7
  162. package/dist/lib/browser/intent-resolver-FK2MDVDT.mjs.map +0 -7
  163. package/dist/lib/browser/react-root-NK3A4VG7.mjs +0 -27
  164. package/dist/lib/node/ChannelContainer-YS5YT2ML.cjs +0 -36
  165. package/dist/lib/node/ChannelContainer-YS5YT2ML.cjs.map +0 -7
  166. package/dist/lib/node/ChatContainer-GCOM3M56.cjs +0 -35
  167. package/dist/lib/node/ChatContainer-GCOM3M56.cjs.map +0 -7
  168. package/dist/lib/node/app-graph-builder-PBHJNDQY.cjs +0 -179
  169. package/dist/lib/node/app-graph-builder-PBHJNDQY.cjs.map +0 -7
  170. package/dist/lib/node/call-manager-HV2XJW5O.cjs +0 -37
  171. package/dist/lib/node/call-manager-HV2XJW5O.cjs.map +0 -7
  172. package/dist/lib/node/chunk-44I33JDT.cjs +0 -1731
  173. package/dist/lib/node/chunk-44I33JDT.cjs.map +0 -7
  174. package/dist/lib/node/chunk-4YSNVPWU.cjs +0 -37
  175. package/dist/lib/node/chunk-4YSNVPWU.cjs.map +0 -7
  176. package/dist/lib/node/chunk-E3WBZTTI.cjs +0 -371
  177. package/dist/lib/node/chunk-E3WBZTTI.cjs.map +0 -7
  178. package/dist/lib/node/chunk-ERG7G6FF.cjs +0 -59
  179. package/dist/lib/node/chunk-ERG7G6FF.cjs.map +0 -7
  180. package/dist/lib/node/chunk-FUXJAVFZ.cjs +0 -108
  181. package/dist/lib/node/chunk-FUXJAVFZ.cjs.map +0 -7
  182. package/dist/lib/node/chunk-HLMCEE5K.cjs +0 -41
  183. package/dist/lib/node/chunk-HLMCEE5K.cjs.map +0 -7
  184. package/dist/lib/node/chunk-IP533AMV.cjs +0 -554
  185. package/dist/lib/node/chunk-IP533AMV.cjs.map +0 -7
  186. package/dist/lib/node/chunk-LR5NENBE.cjs +0 -54
  187. package/dist/lib/node/chunk-LR5NENBE.cjs.map +0 -7
  188. package/dist/lib/node/chunk-UM36TPCT.cjs +0 -984
  189. package/dist/lib/node/chunk-UM36TPCT.cjs.map +0 -7
  190. package/dist/lib/node/chunk-ZGDN3XBR.cjs +0 -149
  191. package/dist/lib/node/chunk-ZGDN3XBR.cjs.map +0 -7
  192. package/dist/lib/node/index.cjs +0 -310
  193. package/dist/lib/node/index.cjs.map +0 -7
  194. package/dist/lib/node/intent-resolver-SYSJ5SJG.cjs +0 -363
  195. package/dist/lib/node/intent-resolver-SYSJ5SJG.cjs.map +0 -7
  196. package/dist/lib/node/markdown-GQIPJS2F.cjs +0 -178
  197. package/dist/lib/node/markdown-GQIPJS2F.cjs.map +0 -7
  198. package/dist/lib/node/meta.json +0 -1
  199. package/dist/lib/node/react-root-6HHDMULJ.cjs +0 -51
  200. package/dist/lib/node/react-root-6HHDMULJ.cjs.map +0 -7
  201. package/dist/lib/node/react-surface-NBH42NN2.cjs +0 -122
  202. package/dist/lib/node/react-surface-NBH42NN2.cjs.map +0 -7
  203. package/dist/lib/node/settings-4LQSFEDK.cjs +0 -36
  204. package/dist/lib/node/settings-4LQSFEDK.cjs.map +0 -7
  205. package/dist/lib/node/state-IY5XX3H2.cjs +0 -50
  206. package/dist/lib/node/state-IY5XX3H2.cjs.map +0 -7
  207. package/dist/lib/node/types/index.cjs +0 -38
  208. package/dist/lib/node/types/index.cjs.map +0 -7
  209. package/dist/lib/node-esm/ChannelContainer-O4QJII2P.mjs +0 -16
  210. package/dist/lib/node-esm/chunk-2RNIPFDA.mjs.map +0 -7
  211. package/dist/lib/node-esm/chunk-O3V45YJP.mjs.map +0 -7
  212. package/dist/lib/node-esm/chunk-O63QJPQX.mjs +0 -23
  213. package/dist/lib/node-esm/chunk-P6RLFCNT.mjs +0 -352
  214. package/dist/lib/node-esm/chunk-P6RLFCNT.mjs.map +0 -7
  215. package/dist/lib/node-esm/chunk-UJMPYKT3.mjs.map +0 -7
  216. package/dist/lib/node-esm/chunk-UZWVVFT3.mjs +0 -551
  217. package/dist/lib/node-esm/chunk-UZWVVFT3.mjs.map +0 -7
  218. package/dist/lib/node-esm/chunk-WXNPD542.mjs.map +0 -7
  219. package/dist/lib/node-esm/intent-resolver-BU73VYW3.mjs.map +0 -7
  220. package/dist/types/src/components/CommentContainer.d.ts +0 -13
  221. package/dist/types/src/components/CommentContainer.d.ts.map +0 -1
  222. package/dist/types/src/peers.stories.d.ts +0 -11
  223. package/dist/types/src/peers.stories.d.ts.map +0 -1
  224. package/src/peers.stories.tsx +0 -189
  225. /package/dist/lib/browser/{ChannelContainer-PKFBVENP.mjs.map → ChannelContainer-IY2UIRLF.mjs.map} +0 -0
  226. /package/dist/lib/browser/{ChatContainer-RSOKYAMK.mjs.map → ChatContainer-AIGIWAUG.mjs.map} +0 -0
  227. /package/dist/lib/browser/{app-graph-builder-OY7R7EJP.mjs.map → app-graph-builder-N7BE5TYW.mjs.map} +0 -0
  228. /package/dist/lib/{node-esm/call-manager-UUYXLF4T.mjs.map → browser/call-manager-NIPDYUVD.mjs.map} +0 -0
  229. /package/dist/lib/browser/{chunk-6NBVNXTM.mjs.map → chunk-4OYAYON2.mjs.map} +0 -0
  230. /package/dist/lib/browser/{chunk-IIUTBDVB.mjs.map → chunk-EV4JWI7L.mjs.map} +0 -0
  231. /package/dist/lib/browser/{chunk-JKQUJOTX.mjs.map → chunk-GERVMFQW.mjs.map} +0 -0
  232. /package/dist/lib/browser/{chunk-R5MDLUPC.mjs.map → chunk-LGSDKXPF.mjs.map} +0 -0
  233. /package/dist/lib/browser/{markdown-TE5SWWNJ.mjs.map → markdown-GEXBVJYN.mjs.map} +0 -0
  234. /package/dist/lib/{node-esm/react-root-RUXOAQNW.mjs.map → browser/react-root-X4UIVGTX.mjs.map} +0 -0
  235. /package/dist/lib/{node-esm/react-surface-ELXFYKP6.mjs.map → browser/react-surface-YCYEFBPM.mjs.map} +0 -0
  236. /package/dist/lib/browser/{settings-RB2RSLXV.mjs.map → settings-E32MTL7A.mjs.map} +0 -0
  237. /package/dist/lib/browser/{state-RKL5MSDP.mjs.map → state-H6CYONWE.mjs.map} +0 -0
  238. /package/dist/lib/node-esm/{ChannelContainer-O4QJII2P.mjs.map → ChannelContainer-DET6T5N2.mjs.map} +0 -0
  239. /package/dist/lib/node-esm/{ChatContainer-F6CSADV7.mjs.map → ChatContainer-IQUWU426.mjs.map} +0 -0
  240. /package/dist/lib/node-esm/{app-graph-builder-BAHBHYWI.mjs.map → app-graph-builder-VCW76Z6V.mjs.map} +0 -0
  241. /package/dist/lib/node-esm/{chunk-PGRP3O4O.mjs.map → chunk-57XR3LEF.mjs.map} +0 -0
  242. /package/dist/lib/node-esm/{chunk-K4KAUOKT.mjs.map → chunk-75RJ5DJI.mjs.map} +0 -0
  243. /package/dist/lib/node-esm/{chunk-ESQC6SYE.mjs.map → chunk-GRLRWTRU.mjs.map} +0 -0
  244. /package/dist/lib/node-esm/{chunk-O63QJPQX.mjs.map → chunk-GW37AAM4.mjs.map} +0 -0
  245. /package/dist/lib/node-esm/{markdown-HJUWNBLS.mjs.map → markdown-LIJZDK2J.mjs.map} +0 -0
  246. /package/dist/lib/node-esm/{settings-EA7DFSM6.mjs.map → settings-SJ24YG7M.mjs.map} +0 -0
  247. /package/dist/lib/node-esm/{state-6AUTNROZ.mjs.map → state-D7WNDT3N.mjs.map} +0 -0
@@ -7,6 +7,7 @@ import React, { useCallback, useEffect, useMemo, useState, type ChangeEvent } fr
7
7
 
8
8
  import { useCapabilities, useCapability } from '@dxos/app-framework';
9
9
  import { Context } from '@dxos/context';
10
+ import { failUndefined } from '@dxos/debug';
10
11
  import { log } from '@dxos/log';
11
12
  import { useClient } from '@dxos/react-client';
12
13
  import { fullyQualifiedId, getSpace } from '@dxos/react-client/echo';
@@ -20,7 +21,7 @@ import { StackItem } from '@dxos/react-ui-stack';
20
21
  import { Call } from './Call';
21
22
  import ChatContainer from './ChatContainer';
22
23
  import { ThreadCapabilities } from '../capabilities';
23
- import { THREAD_PLUGIN } from '../meta';
24
+ import { meta } from '../meta';
24
25
  import { type ChannelType } from '../types';
25
26
 
26
27
  export type ChannelContainerProps = {
@@ -36,7 +37,7 @@ export type ChannelContainerProps = {
36
37
  export const ChannelContainer = ({ channel, roomId: _roomId, role, fullscreen }: ChannelContainerProps) => {
37
38
  const space = getSpace(channel);
38
39
  const callManager = useCapability(ThreadCapabilities.CallManager);
39
- const roomId = channel ? fullyQualifiedId(channel) : _roomId;
40
+ const roomId = _roomId ?? (channel ? fullyQualifiedId(channel) : failUndefined());
40
41
  const identity = useIdentity();
41
42
  const isNamed = !!identity?.profile?.displayName;
42
43
  const joinSound = useSoundEffect('JoinCall');
@@ -133,7 +134,7 @@ export const ChannelContainer = ({ channel, roomId: _roomId, role, fullscreen }:
133
134
  export default ChannelContainer;
134
135
 
135
136
  const DisplayNameMissing = () => {
136
- const { t } = useTranslation(THREAD_PLUGIN);
137
+ const { t } = useTranslation(meta.id);
137
138
  const client = useClient();
138
139
  const [displayName, setDisplayName] = useState('');
139
140
  const handleChange = useCallback((event: ChangeEvent<HTMLInputElement>) => setDisplayName(event.target.value), []);
@@ -163,10 +164,10 @@ const useChannelToolbarActions = (onJoinCall?: () => void) => {
163
164
  return {
164
165
  nodes: [
165
166
  createMenuItemGroup('root', {
166
- label: ['channel toolbar title', { ns: THREAD_PLUGIN }],
167
+ label: ['channel toolbar title', { ns: meta.id }],
167
168
  }),
168
169
  createMenuAction('video-call', () => onJoinCall?.(), {
169
- label: ['start video call label', { ns: THREAD_PLUGIN }],
170
+ label: ['start video call label', { ns: meta.id }],
170
171
  icon: 'ph--video-camera--regular',
171
172
  type: 'video-call',
172
173
  }),
@@ -4,7 +4,7 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type Meta } from '@storybook/react';
7
+ import { type Meta } from '@storybook/react-vite';
8
8
  import React, { useEffect, useState } from 'react';
9
9
 
10
10
  import { Capabilities, contributes, createSurface, IntentPlugin } from '@dxos/app-framework';
@@ -20,7 +20,7 @@ import { DataType } from '@dxos/schema';
20
20
  import { withLayout, withTheme } from '@dxos/storybook-utils';
21
21
 
22
22
  import { ChatContainer } from './ChatContainer';
23
- import translations from '../translations';
23
+ import { translations } from '../translations';
24
24
  import { ChannelType, ThreadType } from '../types';
25
25
 
26
26
  faker.seed(1);
@@ -60,9 +60,9 @@ const Story = () => {
60
60
 
61
61
  export const Default = {};
62
62
 
63
- const meta: Meta = {
63
+ const meta: Meta<typeof Thread.Root> = {
64
64
  title: 'plugins/plugin-thread/Chat',
65
- component: Thread,
65
+ component: Thread.Root,
66
66
  render: () => <Story />,
67
67
  decorators: [
68
68
  withPluginManager({
@@ -15,9 +15,8 @@ import {
15
15
  MessageTextbox,
16
16
  type MessageTextboxProps,
17
17
  Thread,
18
- ThreadFooter,
18
+ type ThreadRootProps,
19
19
  threadLayout,
20
- type ThreadProps,
21
20
  } from '@dxos/react-ui-thread';
22
21
  import { DataType } from '@dxos/schema';
23
22
  import { isNonNullable } from '@dxos/util';
@@ -25,12 +24,12 @@ import { isNonNullable } from '@dxos/util';
25
24
  import { MessageContainer } from './MessageContainer';
26
25
  import { command } from './command-extension';
27
26
  import { useStatus } from '../hooks';
28
- import { THREAD_PLUGIN } from '../meta';
27
+ import { meta } from '../meta';
29
28
  import { type ThreadType } from '../types';
30
29
  import { getMessageMetadata } from '../util';
31
30
 
32
31
  export const ChatHeading = ({ attendableId }: { attendableId?: string }) => {
33
- const { t } = useTranslation(THREAD_PLUGIN);
32
+ const { t } = useTranslation(meta.id);
34
33
  return (
35
34
  <div role='none' className='flex items-center'>
36
35
  <StackItem.SigilButton attendableId={attendableId}>
@@ -46,14 +45,14 @@ export type ChatContainerProps = {
46
45
  thread: ThreadType;
47
46
  context?: Obj.Any;
48
47
  autoFocusTextbox?: boolean;
49
- } & Pick<ThreadProps, 'current'>;
48
+ } & Pick<ThreadRootProps, 'current'>;
50
49
 
51
50
  export const ChatContainer = ({ space, thread, context, current, autoFocusTextbox }: ChatContainerProps) => {
51
+ const { t } = useTranslation(meta.id);
52
52
  const id = fullyQualifiedId(thread);
53
53
  const identity = useIdentity()!;
54
54
  const members = useMembers(space?.key);
55
55
  const activity = useStatus(space, id);
56
- const { t } = useTranslation(THREAD_PLUGIN);
57
56
  // TODO(wittjosiah): This is a hack to reset the editor after a message is sent.
58
57
  const [_count, _setCount] = useState(0);
59
58
  const rerenderEditor = () => _setCount((count) => count + 1);
@@ -93,9 +92,9 @@ export const ChatContainer = ({ space, thread, context, current, autoFocusTextbo
93
92
  thread.messages.push(
94
93
  Ref.make(
95
94
  Obj.make(DataType.Message, {
96
- sender: { identityDid: identity.did },
97
95
  created: new Date().toISOString(),
98
- blocks: [{ type: 'text', text: messageRef.current }],
96
+ sender: { identityDid: identity.did },
97
+ blocks: [{ _tag: 'text', text: messageRef.current }],
99
98
  properties: context ? { context: Ref.make(context) } : undefined,
100
99
  }),
101
100
  ),
@@ -109,7 +108,7 @@ export const ChatContainer = ({ space, thread, context, current, autoFocusTextbo
109
108
  };
110
109
 
111
110
  return (
112
- <Thread
111
+ <Thread.Root
113
112
  current={current}
114
113
  id={id}
115
114
  classNames='bs-full grid-rows-[1fr_min-content_min-content] overflow-hidden transition-[padding-block-end] [[data-sidebar-inline-start-state=open]_&]:lg:pbe-0'
@@ -131,9 +130,11 @@ export const ChatContainer = ({ space, thread, context, current, autoFocusTextbo
131
130
  </ScrollArea.Scrollbar>
132
131
  </ScrollArea.Viewport>
133
132
  </ScrollArea.Root>
133
+
134
134
  <MessageTextbox extensions={extensions} autoFocus={autoFocus} onSend={handleCreate} {...textboxMetadata} />
135
- <ThreadFooter activity={activity}>{t('activity message')}</ThreadFooter>
136
- </Thread>
135
+
136
+ <Thread.Status activity={activity}>{t('activity message')}</Thread.Status>
137
+ </Thread.Root>
137
138
  );
138
139
  };
139
140
 
@@ -4,29 +4,29 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type Meta } from '@storybook/react';
7
+ import { type Meta } from '@storybook/react-vite';
8
8
  import React, { useEffect } from 'react';
9
9
 
10
10
  import { IntentPlugin } from '@dxos/app-framework';
11
11
  import { withPluginManager } from '@dxos/app-framework/testing';
12
12
  import { Obj, Query, Relation, Type } from '@dxos/echo';
13
+ import { ClientPlugin } from '@dxos/plugin-client';
13
14
  import { faker } from '@dxos/random';
14
15
  import { useQuery, useSpace } from '@dxos/react-client/echo';
15
16
  import { useIdentity } from '@dxos/react-client/halo';
16
- import { type ClientRepeatedComponentProps, ClientRepeater } from '@dxos/react-client/testing';
17
17
  import { AnchoredTo, DataType } from '@dxos/schema';
18
- import { withLayout, withTheme } from '@dxos/storybook-utils';
18
+ import { layoutCentered, render, withLayout, withTheme } from '@dxos/storybook-utils';
19
19
 
20
20
  import { CommentsContainer } from './CommentsContainer';
21
21
  import { createCommentThread } from './testing';
22
- import translations from '../translations';
22
+ import { translations } from '../translations';
23
23
  import { ThreadType } from '../types';
24
24
 
25
25
  faker.seed(1);
26
26
 
27
- const Story = ({ spaceKey }: ClientRepeatedComponentProps) => {
27
+ const DefaultStory = () => {
28
28
  const identity = useIdentity();
29
- const space = useSpace(spaceKey);
29
+ const space = useSpace();
30
30
  const anchors = useQuery(space, Query.type(AnchoredTo));
31
31
 
32
32
  useEffect(() => {
@@ -58,26 +58,33 @@ const Story = ({ spaceKey }: ClientRepeatedComponentProps) => {
58
58
  }
59
59
 
60
60
  return (
61
- <div className='flex justify-center overflow-y-auto bg-white dark:bg-black'>
62
- <div className='flex flex-col w-[30rem]'>
63
- <CommentsContainer anchors={anchors} onThreadDelete={console.log} />
64
- </div>
61
+ <div className='w-[30rem] overflow-y-auto bg-baseSurface'>
62
+ <CommentsContainer anchors={anchors} onThreadDelete={console.log} />
65
63
  </div>
66
64
  );
67
65
  };
68
66
 
69
67
  const meta: Meta = {
70
68
  title: 'plugins/plugin-thread/Comments',
71
- // TODO(wittjosiah): Use decorator.
72
- render: () => <ClientRepeater component={Story} createIdentity createSpace types={[ThreadType, DataType.Message]} />,
69
+ render: render(DefaultStory),
73
70
  decorators: [
74
71
  withTheme,
75
- withLayout({ fullscreen: true }),
72
+ withLayout({ fullscreen: true, classNames: layoutCentered }),
76
73
  withPluginManager({
77
- plugins: [IntentPlugin()],
74
+ plugins: [
75
+ IntentPlugin(),
76
+ ClientPlugin({
77
+ types: [DataType.Message, ThreadType, AnchoredTo],
78
+ onClientInitialized: async (_, client) => {
79
+ await client.halo.createIdentity();
80
+ },
81
+ }),
82
+ ],
78
83
  }),
79
84
  ],
80
- parameters: { translations },
85
+ parameters: {
86
+ translations,
87
+ },
81
88
  };
82
89
 
83
90
  export default meta;
@@ -9,21 +9,22 @@ import { fullyQualifiedId } from '@dxos/react-client/echo';
9
9
  import { Callout, Icon, Trans, useTranslation } from '@dxos/react-ui';
10
10
  import { type AnchoredTo } from '@dxos/schema';
11
11
 
12
- import { CommentContainer, type CommentContainerProps } from './CommentContainer';
13
- import { THREAD_PLUGIN } from '../meta';
12
+ import { CommentsThreadContainer, type CommentsThreadContainerProps } from './CommentsThreadContainer';
13
+ import { meta } from '../meta';
14
14
  import { type ThreadType } from '../types';
15
15
 
16
- export type ThreadsContainerProps = Omit<CommentContainerProps, 'anchor' | 'current'> & {
16
+ export type CommentsContainerProps = Omit<CommentsThreadContainerProps, 'anchor' | 'current'> & {
17
17
  anchors: AnchoredTo[];
18
18
  currentId?: string;
19
19
  showResolvedThreads?: boolean;
20
20
  };
21
21
 
22
22
  /**
23
- * Comment threads.
23
+ * Root container for collection of comment threads.
24
24
  */
25
- export const CommentsContainer = ({ anchors, currentId, showResolvedThreads, ...props }: ThreadsContainerProps) => {
26
- const { t } = useTranslation(THREAD_PLUGIN);
25
+ export const CommentsContainer = ({ anchors, currentId, showResolvedThreads, ...props }: CommentsContainerProps) => {
26
+ const { t } = useTranslation(meta.id);
27
+
27
28
  // TODO(wittjosiah): There seems to be a race between thread and anchor being deleted.
28
29
  const filteredAnchors = showResolvedThreads
29
30
  ? anchors.filter((anchor) => !!Relation.getSource(anchor))
@@ -58,9 +59,13 @@ export const CommentsContainer = ({ anchors, currentId, showResolvedThreads, ...
58
59
  );
59
60
  }
60
61
 
61
- return filteredAnchors.map((anchor) => {
62
- const thread = Relation.getSource(anchor) as ThreadType;
63
- const threadId = fullyQualifiedId(thread);
64
- return <CommentContainer key={threadId} anchor={anchor} current={currentId === threadId} {...props} />;
65
- });
62
+ return (
63
+ <div>
64
+ {filteredAnchors.map((anchor) => {
65
+ const thread = Relation.getSource(anchor) as ThreadType;
66
+ const threadId = fullyQualifiedId(thread);
67
+ return <CommentsThreadContainer key={threadId} anchor={anchor} current={currentId === threadId} {...props} />;
68
+ })}
69
+ </div>
70
+ );
66
71
  };
@@ -2,97 +2,38 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { CheckCircle, X } from '@phosphor-icons/react';
6
5
  import React, { useCallback, useMemo, useRef, useState } from 'react';
7
6
 
8
- import { Relation } from '@dxos/echo';
9
- import { RefArray } from '@dxos/live-object';
7
+ import { Ref, Relation } from '@dxos/echo';
10
8
  import { fullyQualifiedId, getSpace, useMembers } from '@dxos/react-client/echo';
11
9
  import { useIdentity } from '@dxos/react-client/halo';
12
- import { Button, Tag, Tooltip, useThemeContext, useTranslation } from '@dxos/react-ui';
10
+ import { IconButton, Tag, Tooltip, useThemeContext, useTranslation } from '@dxos/react-ui';
13
11
  import { createBasicExtensions, createThemeExtensions, listener } from '@dxos/react-ui-editor';
14
- import {
15
- getSize,
16
- hoverableControlItem,
17
- hoverableControls,
18
- hoverableFocusedWithinControls,
19
- mx,
20
- } from '@dxos/react-ui-theme';
21
- import {
22
- MessageTextbox,
23
- type MessageTextboxProps,
24
- Thread,
25
- ThreadFooter,
26
- ThreadHeading,
27
- type ThreadProps,
28
- } from '@dxos/react-ui-thread';
12
+ import { hoverableControlItem, hoverableControls, hoverableFocusedWithinControls, mx } from '@dxos/react-ui-theme';
13
+ import { MessageTextbox, type MessageTextboxProps, Thread, type ThreadRootProps } from '@dxos/react-ui-thread';
29
14
  import { type AnchoredTo } from '@dxos/schema';
30
15
  import { isNonNullable } from '@dxos/util';
31
16
 
32
17
  import { MessageContainer } from './MessageContainer';
33
18
  import { command } from './command-extension';
34
19
  import { useStatus } from '../hooks';
35
- import { THREAD_PLUGIN } from '../meta';
20
+ import { meta } from '../meta';
36
21
  import { type ThreadType } from '../types';
37
22
  import { getMessageMetadata } from '../util';
38
23
 
39
- const sizeClass = getSize(4);
24
+ // TODO(burdon): Remove need for p-1.
25
+ export const commentControlClassNames = '!p-1 transition-opacity';
40
26
 
41
- // TODO(thure): #8149
42
- const commentControlClassNames = '!p-1 !min-bs-0 transition-opacity';
43
-
44
- const ToggleResolvedButton = ({
45
- isResolved,
46
- onResolve,
47
- }: {
48
- isResolved: boolean | undefined;
49
- onResolve: () => void;
50
- }) => {
51
- const { t } = useTranslation(THREAD_PLUGIN);
52
- const label = t(isResolved ? 'mark as unresolved label' : 'mark as resolved label');
53
- return (
54
- <Tooltip.Trigger asChild content={label}>
55
- <Button
56
- variant='ghost'
57
- data-testid='thread.toggle-resolved'
58
- onClick={onResolve}
59
- classNames={[commentControlClassNames, !isResolved && hoverableControlItem]}
60
- >
61
- <span className='sr-only'>{label}</span>
62
- {isResolved ? <CheckCircle className={sizeClass} weight='fill' /> : <CheckCircle className={sizeClass} />}
63
- </Button>
64
- </Tooltip.Trigger>
65
- );
66
- };
67
-
68
- const DeleteThreadButton = ({ onDelete }: { onDelete: () => void }) => {
69
- const { t } = useTranslation(THREAD_PLUGIN);
70
- const label = t('delete thread label');
71
- return (
72
- <Tooltip.Trigger asChild content={label}>
73
- <Button
74
- variant='ghost'
75
- data-testid='thread.delete'
76
- onClick={onDelete}
77
- classNames={[commentControlClassNames, hoverableControlItem]}
78
- >
79
- <span className='sr-only'>{label}</span>
80
- <X className={sizeClass} />
81
- </Button>
82
- </Tooltip.Trigger>
83
- );
84
- };
85
-
86
- export type CommentContainerProps = {
27
+ export type CommentsThreadContainerProps = {
87
28
  anchor: AnchoredTo;
88
29
  onAttend?: (anchor: AnchoredTo) => void;
89
30
  onComment?: (anchor: AnchoredTo, message: string) => void;
90
31
  onResolve?: (anchor: AnchoredTo) => void;
91
32
  onMessageDelete?: (anchor: AnchoredTo, messageId: string) => void;
92
33
  onThreadDelete?: (anchor: AnchoredTo) => void;
93
- } & Pick<ThreadProps, 'current'>;
34
+ } & Pick<ThreadRootProps, 'current'>;
94
35
 
95
- export const CommentContainer = ({
36
+ export const CommentsThreadContainer = ({
96
37
  anchor,
97
38
  current,
98
39
  onAttend,
@@ -100,14 +41,14 @@ export const CommentContainer = ({
100
41
  onResolve,
101
42
  onMessageDelete,
102
43
  onThreadDelete,
103
- }: CommentContainerProps) => {
44
+ }: CommentsThreadContainerProps) => {
45
+ const { t } = useTranslation(meta.id);
104
46
  const identity = useIdentity()!;
105
47
  const space = getSpace(anchor);
106
48
  const members = useMembers(space?.key);
107
49
  const detached = !anchor.anchor;
108
50
  const thread = Relation.getSource(anchor) as ThreadType;
109
51
  const activity = useStatus(space, fullyQualifiedId(thread));
110
- const { t } = useTranslation(THREAD_PLUGIN);
111
52
  const threadScrollRef = useRef<HTMLDivElement | null>(null);
112
53
  const { themeMode } = useThemeContext();
113
54
 
@@ -149,7 +90,13 @@ export const CommentContainer = ({
149
90
  }, [anchor, identity]);
150
91
 
151
92
  return (
152
- <Thread onClickCapture={handleAttend} onFocusCapture={handleAttend} current={current} id={fullyQualifiedId(thread)}>
93
+ <Thread.Root
94
+ id={fullyQualifiedId(thread)}
95
+ classNames='pbs-2 border-be border-subduedSeparator last:border-none'
96
+ current={current}
97
+ onClickCapture={handleAttend}
98
+ onFocusCapture={handleAttend}
99
+ >
153
100
  <div
154
101
  role='none'
155
102
  className={mx(
@@ -160,21 +107,40 @@ export const CommentContainer = ({
160
107
  >
161
108
  {detached ? (
162
109
  <Tooltip.Trigger asChild content={t('detached thread label')} side='top'>
163
- <ThreadHeading detached>{thread.name}</ThreadHeading>
110
+ <Thread.Header detached>{thread.name}</Thread.Header>
164
111
  </Tooltip.Trigger>
165
112
  ) : (
166
- <ThreadHeading>{thread.name}</ThreadHeading>
113
+ <Thread.Header>{thread.name}</Thread.Header>
167
114
  )}
168
- <div className='flex flex-row items-center pli-1'>
115
+ <div className='flex flex-row items-center gap-0.5'>
169
116
  {thread.status === 'staged' && <Tag palette='neutral'>{t('draft button')}</Tag>}
170
117
  {onResolve && !(thread?.status === 'staged') && (
171
- <ToggleResolvedButton isResolved={thread?.status === 'resolved'} onResolve={handleResolve} />
118
+ <IconButton
119
+ data-testid='thread.resolve'
120
+ variant='ghost'
121
+ icon={thread?.status === 'resolved' ? 'ph--check--fill' : 'ph--check--regular'}
122
+ iconOnly
123
+ label={t('resolve thread label')}
124
+ classNames={[commentControlClassNames, thread?.status !== 'resolved' && hoverableControlItem]}
125
+ onClick={handleResolve}
126
+ />
127
+ )}
128
+ {onThreadDelete && (
129
+ <IconButton
130
+ data-testid='thread.delete'
131
+ variant='ghost'
132
+ icon='ph--x--regular'
133
+ iconOnly
134
+ label={t('delete thread label')}
135
+ classNames={[commentControlClassNames, hoverableControlItem]}
136
+ onClick={handleThreadDelete}
137
+ />
172
138
  )}
173
- {onThreadDelete && <DeleteThreadButton onDelete={handleThreadDelete} />}
174
139
  </div>
175
140
  </div>
141
+
176
142
  {/** TODO(dmaretskyi): How's `thread.messages` undefined? */}
177
- {RefArray.targets(thread.messages?.filter(isNonNullable) ?? []).map((message) => (
143
+ {Ref.Array.targets(thread.messages?.filter(isNonNullable) ?? []).map((message) => (
178
144
  <MessageContainer
179
145
  key={message.id}
180
146
  editable
@@ -183,6 +149,7 @@ export const CommentContainer = ({
183
149
  onDelete={handleMessageDelete}
184
150
  />
185
151
  ))}
152
+
186
153
  {/*
187
154
  TODO(wittjosiah): Can't autofocus this generally.
188
155
  There can be multiple threads with inputs and they can't all be focused.
@@ -190,9 +157,11 @@ export const CommentContainer = ({
190
157
  Need to find a way to autofocus in one scenario only: when a new thread is created.
191
158
  */}
192
159
  <MessageTextbox extensions={extensions} onSend={handleComment} {...textboxMetadata} />
193
- <ThreadFooter activity={activity}>{t('activity message')}</ThreadFooter>
160
+
161
+ <Thread.Status activity={activity}>{t('activity message')}</Thread.Status>
162
+
194
163
  {/* NOTE(thure): This can’t also be the `overflow-anchor` because `ScrollArea` injects an interceding node that contains this necessary ref’d element. */}
195
164
  <div role='none' className='bs-px -mbs-px' ref={threadScrollRef} />
196
- </Thread>
165
+ </Thread.Root>
197
166
  );
198
167
  };
@@ -4,7 +4,7 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type StoryObj, type Meta } from '@storybook/react';
7
+ import { type StoryObj, type Meta } from '@storybook/react-vite';
8
8
  import React, { useEffect, useState } from 'react';
9
9
 
10
10
  import { scheduleTask } from '@dxos/async';
@@ -3,35 +3,25 @@
3
3
  //
4
4
 
5
5
  import { EditorView } from '@codemirror/view';
6
- import { Check, PencilSimple, X } from '@phosphor-icons/react';
7
6
  import React, { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
8
7
 
9
8
  import { Surface } from '@dxos/app-framework';
10
- import { type Obj, type Type } from '@dxos/echo';
11
- import { RefArray } from '@dxos/live-object';
9
+ import { type Obj, Ref, type Type } from '@dxos/echo';
12
10
  import { PublicKey } from '@dxos/react-client';
13
11
  import { type SpaceMember } from '@dxos/react-client/echo';
14
12
  import { useIdentity, type Identity } from '@dxos/react-client/halo';
15
- import { Button, ButtonGroup, Tooltip, useOnTransition, useThemeContext, useTranslation } from '@dxos/react-ui';
13
+ import { IconButton, useOnTransition, useThemeContext, useTranslation } from '@dxos/react-ui';
16
14
  import { createBasicExtensions, createThemeExtensions, useTextEditor } from '@dxos/react-ui-editor';
17
- import {
18
- getSize,
19
- hoverableControlItem,
20
- hoverableControls,
21
- hoverableFocusedWithinControls,
22
- mx,
23
- } from '@dxos/react-ui-theme';
15
+ import { hoverableControlItem, hoverableControls, hoverableFocusedWithinControls, mx } from '@dxos/react-ui-theme';
24
16
  import { MessageHeading, MessageRoot } from '@dxos/react-ui-thread';
25
17
  import { type DataType } from '@dxos/schema';
26
18
 
19
+ import { commentControlClassNames } from './CommentsThreadContainer';
27
20
  import { command } from './command-extension';
28
21
  import { useOnEditAnalytics } from '../hooks';
29
- import { THREAD_PLUGIN } from '../meta';
22
+ import { meta } from '../meta';
30
23
  import { getMessageMetadata } from '../util';
31
24
 
32
- // TODO(thure): #8149
33
- const messageControlClassNames = ['!p-1 !min-bs-0 transition-opacity', hoverableControlItem];
34
-
35
25
  export type MessageContainerProps = {
36
26
  message: DataType.Message;
37
27
  members: SpaceMember[];
@@ -40,6 +30,7 @@ export type MessageContainerProps = {
40
30
  };
41
31
 
42
32
  export const MessageContainer = ({ message, members, editable = false, onDelete }: MessageContainerProps) => {
33
+ const { t } = useTranslation(meta.id);
43
34
  const senderIdentity = members.find(
44
35
  (member) =>
45
36
  (message.sender.identityDid && member.identity.did === message.sender.identityDid) ||
@@ -49,48 +40,41 @@ export const MessageContainer = ({ message, members, editable = false, onDelete
49
40
  const userIsAuthor = useIdentity()?.did === messageMetadata.authorId;
50
41
  const [editing, setEditing] = useState(false);
51
42
  const handleDelete = useCallback(() => onDelete?.(message.id), [message, onDelete]);
52
- const { t } = useTranslation(THREAD_PLUGIN);
53
- const editLabel = t(editing ? 'save message label' : 'edit message label');
54
- const deleteLabel = t('delete message label');
55
- const textBlock = message.blocks.find((block) => block.type === 'text');
56
- const references = message.blocks.filter((block) => block.type === 'reference').map((block) => block.reference);
43
+ const textBlock = message.blocks.find((block) => block._tag === 'text');
44
+ const references = message.blocks.filter((block) => block._tag === 'reference').map((block) => block.reference);
57
45
 
58
46
  useOnEditAnalytics(message, textBlock, !!editing);
59
47
 
60
48
  return (
61
49
  <MessageRoot {...messageMetadata} classNames={[hoverableControls, hoverableFocusedWithinControls]}>
62
50
  <MessageHeading authorName={messageMetadata.authorName} timestamp={messageMetadata.timestamp}>
63
- <ButtonGroup classNames='mie-1'>
51
+ <div className='flex flex-row items-center gap-0.5'>
64
52
  {userIsAuthor && editable && (
65
- <Tooltip.Trigger asChild content={editLabel}>
66
- <Button
67
- variant='ghost'
68
- data-testid={editing ? 'thread.message.save' : 'thread.message.edit'}
69
- classNames={messageControlClassNames}
70
- onClick={() => setEditing((editing) => !editing)}
71
- >
72
- <span className='sr-only'>{editLabel}</span>
73
- {editing ? <Check className={getSize(4)} /> : <PencilSimple className={getSize(4)} />}
74
- </Button>
75
- </Tooltip.Trigger>
53
+ <IconButton
54
+ data-testid={editing ? 'thread.message.save' : 'thread.message.edit'}
55
+ variant='ghost'
56
+ icon={editing ? 'ph--check--regular' : 'ph--pencil-simple--regular'}
57
+ iconOnly
58
+ label={t(editing ? 'save message label' : 'edit message label')}
59
+ classNames={[commentControlClassNames, hoverableControlItem]}
60
+ onClick={() => setEditing((editing) => !editing)}
61
+ />
76
62
  )}
77
63
  {onDelete && (
78
- <Tooltip.Trigger asChild content={deleteLabel}>
79
- <Button
80
- variant='ghost'
81
- data-testid='thread.message.delete'
82
- classNames={messageControlClassNames}
83
- onClick={() => handleDelete()}
84
- >
85
- <span className='sr-only'>{deleteLabel}</span>
86
- <X className={getSize(4)} />
87
- </Button>
88
- </Tooltip.Trigger>
64
+ <IconButton
65
+ data-testid='thread.message.delete'
66
+ variant='ghost'
67
+ icon='ph--x--regular'
68
+ iconOnly
69
+ label={t('delete message label')}
70
+ classNames={[commentControlClassNames, hoverableControlItem]}
71
+ onClick={() => handleDelete()}
72
+ />
89
73
  )}
90
- </ButtonGroup>
74
+ </div>
91
75
  </MessageHeading>
92
76
  {textBlock && <TextboxBlock block={textBlock} isAuthor={userIsAuthor} editing={editing} />}
93
- {RefArray.targets(references).map((reference, index) => (
77
+ {Ref.Array.targets(references).map((reference, index) => (
94
78
  <MessagePart key={index} part={reference} />
95
79
  ))}
96
80
  </MessageRoot>
@@ -4,13 +4,13 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type StoryObj, type Meta } from '@storybook/react';
7
+ import { type StoryObj, type Meta } from '@storybook/react-vite';
8
8
  import React from 'react';
9
9
 
10
10
  import { withTheme, withLayout } from '@dxos/storybook-utils';
11
11
 
12
12
  import { ResponsiveContainer } from './ResponsiveContainer';
13
- import translations from '../../translations';
13
+ import { translations } from '../../translations';
14
14
  import { VideoObject as VideoObjectComponent } from '../Media';
15
15
 
16
16
  const meta: Meta<typeof ResponsiveContainer> = {