@dxos/plugin-thread 0.8.2-main.fbd8ed0 → 0.8.2-staging.42af850

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 (385) hide show
  1. package/dist/lib/browser/ChannelContainer-LGYSQMC7.mjs +15 -0
  2. package/dist/lib/browser/ChatContainer-JWRI73OG.mjs +14 -0
  3. package/dist/lib/browser/app-graph-builder-K3CFBN7V.mjs +171 -0
  4. package/dist/lib/browser/app-graph-builder-K3CFBN7V.mjs.map +7 -0
  5. package/dist/lib/browser/call-manager-APQAZWHT.mjs +23 -0
  6. package/dist/lib/browser/call-manager-APQAZWHT.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-4H4A264L.mjs +1708 -0
  8. package/dist/lib/browser/chunk-4H4A264L.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-32EIWOAL.mjs → chunk-5P5BH5GE.mjs} +57 -35
  10. package/dist/lib/browser/chunk-5P5BH5GE.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-5PGLGDIP.mjs +983 -0
  12. package/dist/lib/browser/chunk-5PGLGDIP.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-CF2MXRCH.mjs +21 -0
  14. package/dist/lib/browser/chunk-CF2MXRCH.mjs.map +7 -0
  15. package/dist/lib/browser/chunk-G3TS64FP.mjs +351 -0
  16. package/dist/lib/browser/chunk-G3TS64FP.mjs.map +7 -0
  17. package/dist/lib/browser/{chunk-WBJLUUOK.mjs → chunk-IIUTBDVB.mjs} +4 -4
  18. package/dist/lib/browser/chunk-IIUTBDVB.mjs.map +7 -0
  19. package/dist/lib/browser/chunk-JKQUJOTX.mjs +31 -0
  20. package/dist/lib/browser/chunk-JKQUJOTX.mjs.map +7 -0
  21. package/dist/lib/browser/chunk-KMVGJG23.mjs +545 -0
  22. package/dist/lib/browser/chunk-KMVGJG23.mjs.map +7 -0
  23. package/dist/lib/browser/{chunk-EP6MRLY7.mjs → chunk-R5MDLUPC.mjs} +5 -3
  24. package/dist/lib/browser/chunk-R5MDLUPC.mjs.map +7 -0
  25. package/dist/lib/browser/chunk-WDOQXTI2.mjs +126 -0
  26. package/dist/lib/browser/chunk-WDOQXTI2.mjs.map +7 -0
  27. package/dist/lib/browser/index.mjs +101 -35
  28. package/dist/lib/browser/index.mjs.map +4 -4
  29. package/dist/lib/browser/{intent-resolver-PDOLX5B7.mjs → intent-resolver-YUYZCTLF.mjs} +95 -62
  30. package/dist/lib/browser/intent-resolver-YUYZCTLF.mjs.map +7 -0
  31. package/dist/lib/browser/markdown-4EC3OCF2.mjs +169 -0
  32. package/dist/lib/browser/markdown-4EC3OCF2.mjs.map +7 -0
  33. package/dist/lib/browser/meta.json +1 -1
  34. package/dist/lib/browser/react-root-EECCWHCW.mjs +27 -0
  35. package/dist/lib/browser/react-root-EECCWHCW.mjs.map +7 -0
  36. package/dist/lib/browser/react-surface-5QLZAFDL.mjs +108 -0
  37. package/dist/lib/browser/react-surface-5QLZAFDL.mjs.map +7 -0
  38. package/dist/lib/browser/{settings-K56QXNJ4.mjs → settings-KVBQQSO5.mjs} +3 -3
  39. package/dist/lib/browser/{state-KBGI3QTR.mjs → state-RKL5MSDP.mjs} +4 -4
  40. package/dist/lib/browser/{state-KBGI3QTR.mjs.map → state-RKL5MSDP.mjs.map} +3 -3
  41. package/dist/lib/browser/types/index.mjs +16 -0
  42. package/dist/lib/browser/types/index.mjs.map +7 -0
  43. package/dist/lib/node/ChannelContainer-5EKNEH56.cjs +36 -0
  44. package/dist/lib/node/ChannelContainer-5EKNEH56.cjs.map +7 -0
  45. package/dist/lib/node/ChatContainer-EE3FPSYO.cjs +35 -0
  46. package/dist/lib/node/ChatContainer-EE3FPSYO.cjs.map +7 -0
  47. package/dist/lib/node/app-graph-builder-IRE3GYKE.cjs +179 -0
  48. package/dist/lib/node/app-graph-builder-IRE3GYKE.cjs.map +7 -0
  49. package/dist/lib/node/call-manager-HV2XJW5O.cjs +37 -0
  50. package/dist/lib/node/call-manager-HV2XJW5O.cjs.map +7 -0
  51. package/dist/lib/node/chunk-44I33JDT.cjs +1731 -0
  52. package/dist/lib/node/chunk-44I33JDT.cjs.map +7 -0
  53. package/dist/lib/node/chunk-4B3PPXA6.cjs +371 -0
  54. package/dist/lib/node/chunk-4B3PPXA6.cjs.map +7 -0
  55. package/dist/lib/node/{chunk-NQ5DTPOY.cjs → chunk-4YSNVPWU.cjs} +10 -8
  56. package/dist/lib/node/chunk-4YSNVPWU.cjs.map +7 -0
  57. package/dist/lib/node/chunk-6B3M6XRE.cjs +984 -0
  58. package/dist/lib/node/chunk-6B3M6XRE.cjs.map +7 -0
  59. package/dist/lib/node/{chunk-NO6WQR36.cjs → chunk-FUXJAVFZ.cjs} +50 -29
  60. package/dist/lib/node/chunk-FUXJAVFZ.cjs.map +7 -0
  61. package/dist/lib/node/{chunk-ONLWOUYZ.cjs → chunk-HLMCEE5K.cjs} +7 -7
  62. package/dist/lib/node/{chunk-ONLWOUYZ.cjs.map → chunk-HLMCEE5K.cjs.map} +2 -2
  63. package/dist/lib/node/chunk-JLHENFGK.cjs +549 -0
  64. package/dist/lib/node/chunk-JLHENFGK.cjs.map +7 -0
  65. package/dist/lib/node/chunk-LR5NENBE.cjs +54 -0
  66. package/dist/lib/node/chunk-LR5NENBE.cjs.map +7 -0
  67. package/dist/lib/node/chunk-TKHJVC2C.cjs +147 -0
  68. package/dist/lib/node/chunk-TKHJVC2C.cjs.map +7 -0
  69. package/dist/lib/node/{chunk-AZ275P4V.cjs → chunk-U7NOIXN6.cjs} +16 -10
  70. package/dist/lib/node/chunk-U7NOIXN6.cjs.map +7 -0
  71. package/dist/lib/node/index.cjs +136 -74
  72. package/dist/lib/node/index.cjs.map +4 -4
  73. package/dist/lib/node/{intent-resolver-MNTL32W2.cjs → intent-resolver-MZ3HADNY.cjs} +107 -76
  74. package/dist/lib/node/intent-resolver-MZ3HADNY.cjs.map +7 -0
  75. package/dist/lib/node/markdown-NJDPXIKD.cjs +178 -0
  76. package/dist/lib/node/markdown-NJDPXIKD.cjs.map +7 -0
  77. package/dist/lib/node/meta.json +1 -1
  78. package/dist/lib/node/react-root-IAYQ2DBO.cjs +51 -0
  79. package/dist/lib/node/react-root-IAYQ2DBO.cjs.map +7 -0
  80. package/dist/lib/node/react-surface-AVC5VVIS.cjs +122 -0
  81. package/dist/lib/node/react-surface-AVC5VVIS.cjs.map +7 -0
  82. package/dist/lib/node/{settings-4WLSO726.cjs → settings-H45P5YO2.cjs} +8 -8
  83. package/dist/lib/node/{state-FOHMAVSU.cjs → state-IY5XX3H2.cjs} +8 -8
  84. package/dist/lib/node/{state-FOHMAVSU.cjs.map → state-IY5XX3H2.cjs.map} +3 -3
  85. package/dist/lib/node/{types.cjs → types/index.cjs} +12 -6
  86. package/dist/lib/node/types/index.cjs.map +7 -0
  87. package/dist/lib/node-esm/ChannelContainer-KFS2RWWW.mjs +16 -0
  88. package/dist/lib/node-esm/ChannelContainer-KFS2RWWW.mjs.map +7 -0
  89. package/dist/lib/node-esm/ChatContainer-UJYPQMLV.mjs +15 -0
  90. package/dist/lib/node-esm/ChatContainer-UJYPQMLV.mjs.map +7 -0
  91. package/dist/lib/node-esm/app-graph-builder-I5VMPLE4.mjs +172 -0
  92. package/dist/lib/node-esm/app-graph-builder-I5VMPLE4.mjs.map +7 -0
  93. package/dist/lib/node-esm/call-manager-UUYXLF4T.mjs +24 -0
  94. package/dist/lib/node-esm/call-manager-UUYXLF4T.mjs.map +7 -0
  95. package/dist/lib/node-esm/{chunk-42F2DTMM.mjs → chunk-ESQC6SYE.mjs} +4 -4
  96. package/dist/lib/node-esm/chunk-ESQC6SYE.mjs.map +7 -0
  97. package/dist/lib/node-esm/chunk-J323VQ4P.mjs +127 -0
  98. package/dist/lib/node-esm/chunk-J323VQ4P.mjs.map +7 -0
  99. package/dist/lib/node-esm/{chunk-WLY2HMDB.mjs → chunk-K4KAUOKT.mjs} +5 -3
  100. package/dist/lib/node-esm/chunk-K4KAUOKT.mjs.map +7 -0
  101. package/dist/lib/node-esm/chunk-MNJ3V4XM.mjs +546 -0
  102. package/dist/lib/node-esm/chunk-MNJ3V4XM.mjs.map +7 -0
  103. package/dist/lib/node-esm/{chunk-IZWN4KAY.mjs → chunk-O3V45YJP.mjs} +57 -35
  104. package/dist/lib/node-esm/chunk-O3V45YJP.mjs.map +7 -0
  105. package/dist/lib/node-esm/chunk-ODUB4GAB.mjs +23 -0
  106. package/dist/lib/node-esm/chunk-ODUB4GAB.mjs.map +7 -0
  107. package/dist/lib/node-esm/chunk-PGRP3O4O.mjs +33 -0
  108. package/dist/lib/node-esm/chunk-PGRP3O4O.mjs.map +7 -0
  109. package/dist/lib/node-esm/chunk-POKXRTII.mjs +352 -0
  110. package/dist/lib/node-esm/chunk-POKXRTII.mjs.map +7 -0
  111. package/dist/lib/node-esm/chunk-WXNPD542.mjs +1710 -0
  112. package/dist/lib/node-esm/chunk-WXNPD542.mjs.map +7 -0
  113. package/dist/lib/node-esm/chunk-X6AUQDTE.mjs +984 -0
  114. package/dist/lib/node-esm/chunk-X6AUQDTE.mjs.map +7 -0
  115. package/dist/lib/node-esm/index.mjs +101 -35
  116. package/dist/lib/node-esm/index.mjs.map +4 -4
  117. package/dist/lib/node-esm/{intent-resolver-X2FNKFSK.mjs → intent-resolver-CU22OPAH.mjs} +95 -62
  118. package/dist/lib/node-esm/intent-resolver-CU22OPAH.mjs.map +7 -0
  119. package/dist/lib/node-esm/markdown-HRGGO7IA.mjs +170 -0
  120. package/dist/lib/node-esm/markdown-HRGGO7IA.mjs.map +7 -0
  121. package/dist/lib/node-esm/meta.json +1 -1
  122. package/dist/lib/node-esm/react-root-NQMUEI6Z.mjs +28 -0
  123. package/dist/lib/node-esm/react-root-NQMUEI6Z.mjs.map +7 -0
  124. package/dist/lib/node-esm/react-surface-Z4X5VLMY.mjs +109 -0
  125. package/dist/lib/node-esm/react-surface-Z4X5VLMY.mjs.map +7 -0
  126. package/dist/lib/node-esm/{settings-5UA6FBMW.mjs → settings-IJGUOU3F.mjs} +3 -3
  127. package/dist/lib/node-esm/{state-IRLEO2SB.mjs → state-6AUTNROZ.mjs} +4 -4
  128. package/dist/lib/node-esm/{state-IRLEO2SB.mjs.map → state-6AUTNROZ.mjs.map} +3 -3
  129. package/dist/lib/node-esm/types/index.mjs +17 -0
  130. package/dist/lib/node-esm/types/index.mjs.map +7 -0
  131. package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
  132. package/dist/types/src/calls/call-manager.d.ts +77 -0
  133. package/dist/types/src/calls/call-manager.d.ts.map +1 -0
  134. package/dist/types/src/calls/call-swarm-synchronizer.d.ts +66 -0
  135. package/dist/types/src/calls/call-swarm-synchronizer.d.ts.map +1 -0
  136. package/dist/types/src/calls/index.d.ts +7 -0
  137. package/dist/types/src/calls/index.d.ts.map +1 -0
  138. package/dist/types/src/calls/media-manager.d.ts +60 -0
  139. package/dist/types/src/calls/media-manager.d.ts.map +1 -0
  140. package/dist/types/src/calls/speaking-monitor.d.ts +24 -0
  141. package/dist/types/src/calls/speaking-monitor.d.ts.map +1 -0
  142. package/dist/types/src/calls/types.d.ts +45 -0
  143. package/dist/types/src/calls/types.d.ts.map +1 -0
  144. package/dist/types/src/calls/util/audio.d.ts +6 -0
  145. package/dist/types/src/calls/util/audio.d.ts.map +1 -0
  146. package/dist/types/src/calls/util/calls-service.d.ts +72 -0
  147. package/dist/types/src/calls/util/calls-service.d.ts.map +1 -0
  148. package/dist/types/src/calls/util/history-cache.d.ts +11 -0
  149. package/dist/types/src/calls/util/history-cache.d.ts.map +1 -0
  150. package/dist/types/src/calls/util/index.d.ts +5 -0
  151. package/dist/types/src/calls/util/index.d.ts.map +1 -0
  152. package/dist/types/src/calls/util/media.d.ts +6 -0
  153. package/dist/types/src/calls/util/media.d.ts.map +1 -0
  154. package/dist/types/src/calls/util/stub-media-streams.d.ts +18 -0
  155. package/dist/types/src/calls/util/stub-media-streams.d.ts.map +1 -0
  156. package/dist/types/src/calls/util/task-scheduling.d.ts +17 -0
  157. package/dist/types/src/calls/util/task-scheduling.d.ts.map +1 -0
  158. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  159. package/dist/types/src/capabilities/call-manager.d.ts +5 -0
  160. package/dist/types/src/capabilities/call-manager.d.ts.map +1 -0
  161. package/dist/types/src/capabilities/capabilities.d.ts +13 -1
  162. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  163. package/dist/types/src/capabilities/index.d.ts +5 -0
  164. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  165. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  166. package/dist/types/src/capabilities/markdown.d.ts.map +1 -1
  167. package/dist/types/src/capabilities/react-root.d.ts +7 -0
  168. package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
  169. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  170. package/dist/types/src/components/Call/Call.d.ts +17 -0
  171. package/dist/types/src/components/Call/Call.d.ts.map +1 -0
  172. package/dist/types/src/components/Call/Toolbar.d.ts +16 -0
  173. package/dist/types/src/components/Call/Toolbar.d.ts.map +1 -0
  174. package/dist/types/src/components/Call/index.d.ts +3 -0
  175. package/dist/types/src/components/Call/index.d.ts.map +1 -0
  176. package/dist/types/src/components/CallDebugPanel.d.ts +8 -0
  177. package/dist/types/src/components/CallDebugPanel.d.ts.map +1 -0
  178. package/dist/types/src/components/CallSidebar.d.ts +4 -0
  179. package/dist/types/src/components/CallSidebar.d.ts.map +1 -0
  180. package/dist/types/src/components/ChannelContainer.d.ts +14 -0
  181. package/dist/types/src/components/ChannelContainer.d.ts.map +1 -0
  182. package/dist/types/src/components/ChannelContainer.stories.d.ts +10 -0
  183. package/dist/types/src/components/ChannelContainer.stories.d.ts.map +1 -0
  184. package/dist/types/src/components/ChatContainer.d.ts +9 -7
  185. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  186. package/dist/types/src/components/CommentContainer.d.ts +11 -2
  187. package/dist/types/src/components/CommentContainer.d.ts.map +1 -1
  188. package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
  189. package/dist/types/src/components/CommentsContainer.d.ts +5 -9
  190. package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
  191. package/dist/types/src/components/Lobby/Lobby.d.ts +15 -0
  192. package/dist/types/src/components/Lobby/Lobby.d.ts.map +1 -0
  193. package/dist/types/src/components/Lobby/index.d.ts +2 -0
  194. package/dist/types/src/components/Lobby/index.d.ts.map +1 -0
  195. package/dist/types/src/components/Media/AudioStream.d.ts +6 -0
  196. package/dist/types/src/components/Media/AudioStream.d.ts.map +1 -0
  197. package/dist/types/src/components/Media/VideoObject.d.ts +15 -0
  198. package/dist/types/src/components/Media/VideoObject.d.ts.map +1 -0
  199. package/dist/types/src/components/Media/VideoObject.stories.d.ts +8 -0
  200. package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -0
  201. package/dist/types/src/components/Media/index.d.ts +3 -0
  202. package/dist/types/src/components/Media/index.d.ts.map +1 -0
  203. package/dist/types/src/components/Participant/Participant.d.ts +6 -0
  204. package/dist/types/src/components/Participant/Participant.d.ts.map +1 -0
  205. package/dist/types/src/components/Participant/ParticipantGrid.d.ts +11 -0
  206. package/dist/types/src/components/Participant/ParticipantGrid.d.ts.map +1 -0
  207. package/dist/types/src/components/Participant/index.d.ts +3 -0
  208. package/dist/types/src/components/Participant/index.d.ts.map +1 -0
  209. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.d.ts +12 -0
  210. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.d.ts.map +1 -0
  211. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +10 -0
  212. package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +1 -0
  213. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.d.ts +32 -0
  214. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.d.ts.map +1 -0
  215. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +23 -0
  216. package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +1 -0
  217. package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts +21 -0
  218. package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts.map +1 -0
  219. package/dist/types/src/components/ResponsiveGrid/index.d.ts +4 -0
  220. package/dist/types/src/components/ResponsiveGrid/index.d.ts.map +1 -0
  221. package/dist/types/src/components/ThreadComplementary.d.ts.map +1 -1
  222. package/dist/types/src/components/index.d.ts +5 -1
  223. package/dist/types/src/components/index.d.ts.map +1 -1
  224. package/dist/types/src/components/testing.d.ts +14 -14
  225. package/dist/types/src/components/testing.d.ts.map +1 -1
  226. package/dist/types/src/extensions/threads.d.ts.map +1 -1
  227. package/dist/types/src/hooks/index.d.ts +2 -1
  228. package/dist/types/src/hooks/index.d.ts.map +1 -1
  229. package/dist/types/src/hooks/useDebugMode.d.ts +2 -0
  230. package/dist/types/src/hooks/useDebugMode.d.ts.map +1 -0
  231. package/dist/types/src/index.d.ts +1 -1
  232. package/dist/types/src/index.d.ts.map +1 -1
  233. package/dist/types/src/meta.d.ts.map +1 -1
  234. package/dist/types/src/peers.stories.d.ts +11 -0
  235. package/dist/types/src/peers.stories.d.ts.map +1 -0
  236. package/dist/types/src/testing/index.d.ts +2 -0
  237. package/dist/types/src/testing/index.d.ts.map +1 -0
  238. package/dist/types/src/testing/stories.d.ts +2 -0
  239. package/dist/types/src/testing/stories.d.ts.map +1 -0
  240. package/dist/types/src/translations.d.ts +34 -1
  241. package/dist/types/src/translations.d.ts.map +1 -1
  242. package/dist/types/src/types/index.d.ts +3 -0
  243. package/dist/types/src/types/index.d.ts.map +1 -0
  244. package/dist/types/src/types/schema.d.ts +317 -0
  245. package/dist/types/src/types/schema.d.ts.map +1 -0
  246. package/dist/types/src/types/types.d.ts +1015 -0
  247. package/dist/types/src/types/types.d.ts.map +1 -0
  248. package/dist/types/src/util.d.ts +2 -0
  249. package/dist/types/src/util.d.ts.map +1 -1
  250. package/package.json +54 -41
  251. package/src/ThreadPlugin.tsx +28 -9
  252. package/src/calls/call-manager.ts +242 -0
  253. package/src/calls/call-swarm-synchronizer.ts +350 -0
  254. package/src/calls/index.ts +10 -0
  255. package/src/calls/media-manager.ts +342 -0
  256. package/src/calls/speaking-monitor.ts +85 -0
  257. package/src/calls/types.ts +70 -0
  258. package/src/calls/util/audio.ts +58 -0
  259. package/src/calls/util/calls-service.ts +527 -0
  260. package/src/calls/util/history-cache.ts +27 -0
  261. package/src/calls/util/index.ts +8 -0
  262. package/src/calls/util/media.ts +52 -0
  263. package/src/calls/util/stub-media-streams.ts +73 -0
  264. package/src/calls/util/task-scheduling.ts +92 -0
  265. package/src/capabilities/app-graph-builder.ts +148 -12
  266. package/src/capabilities/call-manager.ts +19 -0
  267. package/src/capabilities/capabilities.ts +15 -1
  268. package/src/capabilities/index.ts +2 -0
  269. package/src/capabilities/intent-resolver.ts +69 -47
  270. package/src/capabilities/markdown.ts +51 -1
  271. package/src/capabilities/react-root.tsx +17 -0
  272. package/src/capabilities/react-surface.tsx +52 -27
  273. package/src/capabilities/state.ts +1 -1
  274. package/src/components/Call/Call.tsx +88 -0
  275. package/src/components/Call/Toolbar.tsx +182 -0
  276. package/src/components/Call/index.ts +6 -0
  277. package/src/components/CallDebugPanel.tsx +115 -0
  278. package/src/components/CallSidebar.tsx +17 -0
  279. package/src/components/ChannelContainer.stories.tsx +58 -0
  280. package/src/components/ChannelContainer.tsx +203 -0
  281. package/src/components/Chat.stories.tsx +6 -6
  282. package/src/components/ChatContainer.tsx +36 -24
  283. package/src/components/CommentContainer.tsx +31 -12
  284. package/src/components/Comments.stories.tsx +13 -11
  285. package/src/components/CommentsContainer.tsx +18 -28
  286. package/src/components/Lobby/Lobby.tsx +119 -0
  287. package/src/components/Lobby/index.ts +5 -0
  288. package/src/components/Media/AudioStream.tsx +67 -0
  289. package/src/components/Media/VideoObject.stories.tsx +52 -0
  290. package/src/components/Media/VideoObject.tsx +58 -0
  291. package/src/components/Media/index.ts +6 -0
  292. package/src/components/Participant/Participant.tsx +57 -0
  293. package/src/components/Participant/ParticipantGrid.tsx +88 -0
  294. package/src/components/Participant/index.ts +6 -0
  295. package/src/components/ResponsiveGrid/ResponsiveContainer.stories.tsx +54 -0
  296. package/src/components/ResponsiveGrid/ResponsiveContainer.tsx +31 -0
  297. package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +156 -0
  298. package/src/components/ResponsiveGrid/ResponsiveGrid.tsx +341 -0
  299. package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +131 -0
  300. package/src/components/ResponsiveGrid/index.ts +7 -0
  301. package/src/components/ThreadComplementary.tsx +37 -42
  302. package/src/components/index.ts +4 -0
  303. package/src/components/testing.ts +2 -1
  304. package/src/extensions/threads.ts +42 -24
  305. package/src/hooks/index.ts +2 -1
  306. package/src/hooks/useDebugMode.ts +25 -0
  307. package/src/index.ts +1 -1
  308. package/src/meta.ts +4 -3
  309. package/src/peers.stories.tsx +189 -0
  310. package/src/testing/index.ts +5 -0
  311. package/src/testing/stories.ts +50 -0
  312. package/src/translations.ts +44 -3
  313. package/src/types/index.ts +6 -0
  314. package/src/types/schema.ts +29 -0
  315. package/src/{types.ts → types/types.ts} +24 -14
  316. package/src/typings/peermetrics-webrtc-stats.d.ts +30 -0
  317. package/src/util.ts +12 -0
  318. package/dist/lib/browser/ChatContainer-H4XTHM3A.mjs +0 -138
  319. package/dist/lib/browser/ChatContainer-H4XTHM3A.mjs.map +0 -7
  320. package/dist/lib/browser/app-graph-builder-V7UUHGUI.mjs +0 -44
  321. package/dist/lib/browser/app-graph-builder-V7UUHGUI.mjs.map +0 -7
  322. package/dist/lib/browser/chunk-32EIWOAL.mjs.map +0 -7
  323. package/dist/lib/browser/chunk-EP6MRLY7.mjs.map +0 -7
  324. package/dist/lib/browser/chunk-I3JK6CBS.mjs +0 -209
  325. package/dist/lib/browser/chunk-I3JK6CBS.mjs.map +0 -7
  326. package/dist/lib/browser/chunk-OO7PQPV5.mjs +0 -93
  327. package/dist/lib/browser/chunk-OO7PQPV5.mjs.map +0 -7
  328. package/dist/lib/browser/chunk-WBJLUUOK.mjs.map +0 -7
  329. package/dist/lib/browser/chunk-YRGWE35W.mjs +0 -17
  330. package/dist/lib/browser/chunk-YRGWE35W.mjs.map +0 -7
  331. package/dist/lib/browser/intent-resolver-PDOLX5B7.mjs.map +0 -7
  332. package/dist/lib/browser/markdown-XJJVUBDO.mjs +0 -111
  333. package/dist/lib/browser/markdown-XJJVUBDO.mjs.map +0 -7
  334. package/dist/lib/browser/react-surface-7DJZKIOK.mjs +0 -436
  335. package/dist/lib/browser/react-surface-7DJZKIOK.mjs.map +0 -7
  336. package/dist/lib/browser/types.mjs +0 -10
  337. package/dist/lib/node/ChatContainer-TUISUIY7.cjs +0 -163
  338. package/dist/lib/node/ChatContainer-TUISUIY7.cjs.map +0 -7
  339. package/dist/lib/node/app-graph-builder-MMM26FEH.cjs +0 -60
  340. package/dist/lib/node/app-graph-builder-MMM26FEH.cjs.map +0 -7
  341. package/dist/lib/node/chunk-AZ275P4V.cjs.map +0 -7
  342. package/dist/lib/node/chunk-ETDNE4Z6.cjs +0 -234
  343. package/dist/lib/node/chunk-ETDNE4Z6.cjs.map +0 -7
  344. package/dist/lib/node/chunk-GRMB5VRN.cjs +0 -113
  345. package/dist/lib/node/chunk-GRMB5VRN.cjs.map +0 -7
  346. package/dist/lib/node/chunk-NO6WQR36.cjs.map +0 -7
  347. package/dist/lib/node/chunk-NQ5DTPOY.cjs.map +0 -7
  348. package/dist/lib/node/intent-resolver-MNTL32W2.cjs.map +0 -7
  349. package/dist/lib/node/markdown-25NI6Q4Y.cjs +0 -121
  350. package/dist/lib/node/markdown-25NI6Q4Y.cjs.map +0 -7
  351. package/dist/lib/node/react-surface-KGUZJVRL.cjs +0 -438
  352. package/dist/lib/node/react-surface-KGUZJVRL.cjs.map +0 -7
  353. package/dist/lib/node/types.cjs.map +0 -7
  354. package/dist/lib/node-esm/ChatContainer-G7VTTRDN.mjs +0 -139
  355. package/dist/lib/node-esm/ChatContainer-G7VTTRDN.mjs.map +0 -7
  356. package/dist/lib/node-esm/app-graph-builder-QEFJ2KA4.mjs +0 -45
  357. package/dist/lib/node-esm/app-graph-builder-QEFJ2KA4.mjs.map +0 -7
  358. package/dist/lib/node-esm/chunk-42F2DTMM.mjs.map +0 -7
  359. package/dist/lib/node-esm/chunk-5XUQJWUG.mjs +0 -19
  360. package/dist/lib/node-esm/chunk-5XUQJWUG.mjs.map +0 -7
  361. package/dist/lib/node-esm/chunk-A7RLBTTZ.mjs +0 -94
  362. package/dist/lib/node-esm/chunk-A7RLBTTZ.mjs.map +0 -7
  363. package/dist/lib/node-esm/chunk-IZWN4KAY.mjs.map +0 -7
  364. package/dist/lib/node-esm/chunk-V7HLWNAO.mjs +0 -210
  365. package/dist/lib/node-esm/chunk-V7HLWNAO.mjs.map +0 -7
  366. package/dist/lib/node-esm/chunk-WLY2HMDB.mjs.map +0 -7
  367. package/dist/lib/node-esm/intent-resolver-X2FNKFSK.mjs.map +0 -7
  368. package/dist/lib/node-esm/markdown-2ERASVEO.mjs +0 -112
  369. package/dist/lib/node-esm/markdown-2ERASVEO.mjs.map +0 -7
  370. package/dist/lib/node-esm/react-surface-DLD2UJRM.mjs +0 -437
  371. package/dist/lib/node-esm/react-surface-DLD2UJRM.mjs.map +0 -7
  372. package/dist/lib/node-esm/types.mjs +0 -11
  373. package/dist/types/src/components/types.d.ts +0 -28
  374. package/dist/types/src/components/types.d.ts.map +0 -1
  375. package/dist/types/src/events.d.ts +0 -4
  376. package/dist/types/src/events.d.ts.map +0 -1
  377. package/dist/types/src/types.d.ts +0 -276
  378. package/dist/types/src/types.d.ts.map +0 -1
  379. package/src/components/types.ts +0 -32
  380. package/src/events.ts +0 -11
  381. /package/dist/lib/browser/{types.mjs.map → ChannelContainer-LGYSQMC7.mjs.map} +0 -0
  382. /package/dist/lib/{node-esm/types.mjs.map → browser/ChatContainer-JWRI73OG.mjs.map} +0 -0
  383. /package/dist/lib/browser/{settings-K56QXNJ4.mjs.map → settings-KVBQQSO5.mjs.map} +0 -0
  384. /package/dist/lib/node/{settings-4WLSO726.cjs.map → settings-H45P5YO2.cjs.map} +0 -0
  385. /package/dist/lib/node-esm/{settings-5UA6FBMW.mjs.map → settings-IJGUOU3F.mjs.map} +0 -0
@@ -0,0 +1,203 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Rx } from '@effect-rx/rx-react';
6
+ import React, { useCallback, useEffect, useMemo, useState, type ChangeEvent } from 'react';
7
+
8
+ import { useCapabilities, useCapability } from '@dxos/app-framework';
9
+ import { Context } from '@dxos/context';
10
+ import { log } from '@dxos/log';
11
+ import { useClient } from '@dxos/react-client';
12
+ import { fullyQualifiedId, getSpace } from '@dxos/react-client/echo';
13
+ import { useIdentity } from '@dxos/react-client/halo';
14
+ import { useTranslation, Input, ElevationProvider } from '@dxos/react-ui';
15
+ import { ControlGroup, ControlItemInput, ControlGroupButton } from '@dxos/react-ui-form';
16
+ import { ToolbarMenu, MenuProvider, createMenuAction, useMenuActions, createMenuItemGroup } from '@dxos/react-ui-menu';
17
+ import { useSoundEffect } from '@dxos/react-ui-sfx';
18
+ import { StackItem } from '@dxos/react-ui-stack';
19
+
20
+ import { Call } from './Call';
21
+ import ChatContainer from './ChatContainer';
22
+ import { ThreadCapabilities } from '../capabilities';
23
+ import { THREAD_PLUGIN } from '../meta';
24
+ import { type ChannelType } from '../types';
25
+
26
+ export type ChannelContainerProps = {
27
+ channel?: ChannelType;
28
+ roomId?: string;
29
+ role?: string;
30
+ fullscreen?: boolean;
31
+ };
32
+
33
+ /**
34
+ * Renders a call when active, otherwise renders the channel chat.
35
+ */
36
+ export const ChannelContainer = ({ channel, roomId: _roomId, role, fullscreen }: ChannelContainerProps) => {
37
+ const space = getSpace(channel);
38
+ const callManager = useCapability(ThreadCapabilities.CallManager);
39
+ const roomId = channel ? fullyQualifiedId(channel) : _roomId;
40
+ const identity = useIdentity();
41
+ const isNamed = !!identity?.profile?.displayName;
42
+ const joinSound = useSoundEffect('JoinCall');
43
+ const leaveSound = useSoundEffect('LeaveCall');
44
+
45
+ const extensions = useCapabilities(ThreadCapabilities.CallExtension);
46
+ useEffect(() => {
47
+ const ctx = new Context();
48
+ callManager.left.on(ctx, (roomId) => {
49
+ extensions.forEach((extension) => {
50
+ void extension.onLeave?.(roomId);
51
+ });
52
+ });
53
+
54
+ callManager.callStateUpdated.on(ctx, (state) => {
55
+ extensions.forEach((extension) => {
56
+ void extension.onCallStateUpdated?.(state);
57
+ });
58
+ });
59
+
60
+ callManager.mediaStateUpdated.on(ctx, (state) => {
61
+ extensions.forEach((extension) => {
62
+ void extension.onMediaStateUpdated?.(state);
63
+ });
64
+ });
65
+
66
+ return () => {
67
+ void ctx.dispose();
68
+ };
69
+ }, [callManager, extensions]);
70
+
71
+ /**
72
+ * Join the call.
73
+ */
74
+ // TODO(wittjosiah): Show preview before joining?
75
+ const handleJoin = useCallback(async () => {
76
+ if (!roomId || !channel) {
77
+ return;
78
+ }
79
+
80
+ if (callManager.joined) {
81
+ await callManager.leave();
82
+ }
83
+
84
+ try {
85
+ void joinSound.play();
86
+ callManager.setRoomId(roomId);
87
+ await callManager.join();
88
+ await Promise.all(extensions.map((extension) => extension.onJoin?.({ channel, roomId })));
89
+ } catch (err) {
90
+ // TODO(burdon): Error sound.
91
+ log.catch(err);
92
+ }
93
+ }, [extensions, channel, roomId]);
94
+
95
+ /**
96
+ * Leave the call.
97
+ */
98
+ const handleLeave = useCallback(async () => {
99
+ try {
100
+ void leaveSound.play();
101
+ } catch (err) {
102
+ // TODO(burdon): Error sound.
103
+ log.catch(err);
104
+ } finally {
105
+ void callManager.turnAudioOff();
106
+ void callManager.turnVideoOff();
107
+ void callManager.turnScreenshareOff();
108
+ void callManager.leave();
109
+ }
110
+ }, [extensions, roomId]);
111
+
112
+ const isJoined = callManager.joined && callManager.roomId === roomId;
113
+
114
+ return (
115
+ <StackItem.Content toolbar={!isJoined} classNames={isJoined && 'h-full'}>
116
+ {isJoined && !isNamed && <DisplayNameMissing />}
117
+ {isJoined && isNamed && (
118
+ <Call.Root>
119
+ <Call.Grid fullscreen={fullscreen} />
120
+ <Call.Toolbar channel={channel} onLeave={handleLeave} />
121
+ </Call.Root>
122
+ )}
123
+ {!isJoined && channel && channel.defaultThread.target && space && (
124
+ <>
125
+ <ChannelToolbar attendableId={fullyQualifiedId(channel)} role={role} onJoinCall={handleJoin} />
126
+ <ChatContainer space={space} thread={channel.defaultThread.target} />
127
+ </>
128
+ )}
129
+ </StackItem.Content>
130
+ );
131
+ };
132
+
133
+ export default ChannelContainer;
134
+
135
+ const DisplayNameMissing = () => {
136
+ const { t } = useTranslation(THREAD_PLUGIN);
137
+ const client = useClient();
138
+ const [displayName, setDisplayName] = useState('');
139
+ const handleChange = useCallback((event: ChangeEvent<HTMLInputElement>) => setDisplayName(event.target.value), []);
140
+ const handleSave = useCallback(() => client.halo.updateProfile({ displayName }), [client, displayName]);
141
+
142
+ return (
143
+ <ControlGroup classNames='p-4 place-content-center'>
144
+ <ControlItemInput title={t('display name label')} description={t('display name description')}>
145
+ <Input.TextInput
146
+ value={displayName}
147
+ onChange={handleChange}
148
+ placeholder={t('display name input placeholder')}
149
+ classNames='md:min-is-64'
150
+ />
151
+ </ControlItemInput>
152
+ <ControlGroupButton disabled={!displayName} onClick={handleSave}>
153
+ {t('set display name label')}
154
+ </ControlGroupButton>
155
+ </ControlGroup>
156
+ );
157
+ };
158
+
159
+ const useChannelToolbarActions = (onJoinCall?: () => void) => {
160
+ const creator = useMemo(
161
+ () =>
162
+ Rx.make(() => {
163
+ const nodes = [];
164
+ const edges = [];
165
+
166
+ const rootGroup = createMenuItemGroup('root', {
167
+ label: ['channel toolbar title', { ns: THREAD_PLUGIN }],
168
+ });
169
+ nodes.push(rootGroup);
170
+
171
+ const sortAction = createMenuAction('video-call', () => onJoinCall?.(), {
172
+ label: ['start video call label', { ns: THREAD_PLUGIN }],
173
+ icon: 'ph--video-camera--regular',
174
+ type: 'video-call',
175
+ });
176
+ nodes.push(sortAction);
177
+ edges.push({ source: 'root', target: sortAction.id });
178
+
179
+ return { nodes, edges };
180
+ }),
181
+ [],
182
+ );
183
+
184
+ return useMenuActions(creator);
185
+ };
186
+
187
+ type ChannelToolbarProps = {
188
+ attendableId?: string;
189
+ role?: string;
190
+ onJoinCall?: () => void;
191
+ };
192
+
193
+ const ChannelToolbar = ({ attendableId, role, onJoinCall }: ChannelToolbarProps) => {
194
+ const menuProps = useChannelToolbarActions(onJoinCall);
195
+
196
+ return (
197
+ <ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
198
+ <MenuProvider {...menuProps} attendableId={attendableId}>
199
+ <ToolbarMenu />
200
+ </MenuProvider>
201
+ </ElevationProvider>
202
+ );
203
+ };
@@ -9,9 +9,7 @@ import React, { useEffect, useState } from 'react';
9
9
 
10
10
  import { Capabilities, contributes, createSurface, IntentPlugin } from '@dxos/app-framework';
11
11
  import { withPluginManager } from '@dxos/app-framework/testing';
12
- import { createQueueDxn } from '@dxos/echo-schema';
13
- import { refFromDXN } from '@dxos/live-object';
14
- import { ChannelType, ThreadType } from '@dxos/plugin-space/types';
12
+ import { makeRef } from '@dxos/live-object';
15
13
  import { faker } from '@dxos/random';
16
14
  import { useClient } from '@dxos/react-client';
17
15
  import { live, type Space } from '@dxos/react-client/echo';
@@ -23,6 +21,7 @@ import { withLayout, withTheme } from '@dxos/storybook-utils';
23
21
 
24
22
  import { ChatContainer } from './ChatContainer';
25
23
  import translations from '../translations';
24
+ import { ChannelType, ThreadType } from '../types';
26
25
 
27
26
  faker.seed(1);
28
27
 
@@ -38,7 +37,8 @@ const Story = () => {
38
37
  const space = await client.spaces.create();
39
38
  const channel = space.db.add(
40
39
  live(ChannelType, {
41
- queue: refFromDXN(createQueueDxn(space.id)),
40
+ defaultThread: makeRef(live(ThreadType, { messages: [], status: 'active' })),
41
+ threads: [],
42
42
  }),
43
43
  );
44
44
  setSpace(space);
@@ -47,13 +47,13 @@ const Story = () => {
47
47
  }
48
48
  }, [identity]);
49
49
 
50
- if (!identity || !channel || !space) {
50
+ if (!identity || !channel || !space || !channel.defaultThread.target) {
51
51
  return null;
52
52
  }
53
53
 
54
54
  return (
55
55
  <main className='max-is-prose mli-auto bs-dvh overflow-hidden'>
56
- <ChatContainer space={space} dxn={channel.queue.dxn} />
56
+ <ChatContainer space={space} thread={channel.defaultThread.target} />
57
57
  </main>
58
58
  );
59
59
  };
@@ -4,23 +4,29 @@
4
4
 
5
5
  import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
6
6
 
7
- import { create } from '@dxos/echo-schema';
8
- import { type DXN } from '@dxos/keys';
9
- import { makeRef } from '@dxos/live-object';
10
- import { type Space, useMembers, useQueue } from '@dxos/react-client/echo';
7
+ import { live, makeRef } from '@dxos/live-object';
8
+ import { type AnyLiveObject, fullyQualifiedId, type Space, useMembers } from '@dxos/react-client/echo';
11
9
  import { useIdentity } from '@dxos/react-client/halo';
12
10
  import { Icon, ScrollArea, useThemeContext, useTranslation } from '@dxos/react-ui';
13
11
  import { createBasicExtensions, createThemeExtensions, listener } from '@dxos/react-ui-editor';
14
12
  import { StackItem } from '@dxos/react-ui-stack';
15
13
  import { mx } from '@dxos/react-ui-theme';
16
- import { MessageTextbox, type MessageTextboxProps, Thread, ThreadFooter, threadLayout } from '@dxos/react-ui-thread';
14
+ import {
15
+ MessageTextbox,
16
+ type MessageTextboxProps,
17
+ Thread,
18
+ ThreadFooter,
19
+ threadLayout,
20
+ type ThreadProps,
21
+ } from '@dxos/react-ui-thread';
17
22
  import { DataType } from '@dxos/schema';
23
+ import { isNonNullable } from '@dxos/util';
18
24
 
19
25
  import { MessageContainer } from './MessageContainer';
20
26
  import { command } from './command-extension';
21
- import { type ThreadContainerProps } from './types';
22
27
  import { useStatus } from '../hooks';
23
28
  import { THREAD_PLUGIN } from '../meta';
29
+ import { type ThreadType } from '../types';
24
30
  import { getMessageMetadata } from '../util';
25
31
 
26
32
  export const ChatHeading = ({ attendableId }: { attendableId?: string }) => {
@@ -35,16 +41,17 @@ export const ChatHeading = ({ attendableId }: { attendableId?: string }) => {
35
41
  );
36
42
  };
37
43
 
38
- export type ChatContainerProps = Omit<ThreadContainerProps, 'thread'> & {
44
+ export type ChatContainerProps = {
39
45
  space: Space;
40
- dxn: DXN;
41
- };
46
+ thread: ThreadType;
47
+ context?: AnyLiveObject<any>;
48
+ autoFocusTextbox?: boolean;
49
+ } & Pick<ThreadProps, 'current'>;
42
50
 
43
- export const ChatContainer = ({ space, dxn, context, current, autoFocusTextbox }: ChatContainerProps) => {
44
- const id = dxn.toString();
51
+ export const ChatContainer = ({ space, thread, context, current, autoFocusTextbox }: ChatContainerProps) => {
52
+ const id = fullyQualifiedId(thread);
45
53
  const identity = useIdentity()!;
46
54
  const members = useMembers(space?.key);
47
- const queue = useQueue<DataType.Message>(dxn, { pollInterval: 1_000 });
48
55
  const activity = useStatus(space, id);
49
56
  const { t } = useTranslation(THREAD_PLUGIN);
50
57
  // TODO(wittjosiah): This is a hack to reset the editor after a message is sent.
@@ -79,18 +86,20 @@ export const ChatContainer = ({ space, dxn, context, current, autoFocusTextbox }
79
86
 
80
87
  // TODO(burdon): Change to model.
81
88
  const handleCreate: MessageTextboxProps['onSend'] = () => {
82
- if (!messageRef.current?.length || !queue) {
89
+ if (!messageRef.current?.length) {
83
90
  return false;
84
91
  }
85
92
 
86
- queue.append([
87
- create(DataType.Message, {
88
- sender: { identityDid: identity.did },
89
- created: new Date().toISOString(),
90
- blocks: [{ type: 'text', text: messageRef.current }],
91
- properties: context ? { context: makeRef(context) } : undefined,
92
- }),
93
- ]);
93
+ thread.messages.push(
94
+ makeRef(
95
+ live(DataType.Message, {
96
+ sender: { identityDid: identity.did },
97
+ created: new Date().toISOString(),
98
+ blocks: [{ type: 'text', text: messageRef.current }],
99
+ properties: context ? { context: makeRef(context) } : undefined,
100
+ }),
101
+ ),
102
+ );
94
103
 
95
104
  messageRef.current = '';
96
105
  setAutoFocus(true);
@@ -108,9 +117,12 @@ export const ChatContainer = ({ space, dxn, context, current, autoFocusTextbox }
108
117
  <ScrollArea.Root classNames='col-span-2'>
109
118
  <ScrollArea.Viewport classNames='overflow-anchored after:overflow-anchor after:block after:bs-px after:-mbs-px [&>div]:min-bs-full [&>div]:!grid [&>div]:grid-rows-[1fr_0]'>
110
119
  <div role='none' className={mx(threadLayout, 'place-self-end')}>
111
- {(queue?.items ?? []).map((message) => (
112
- <MessageContainer key={message.id} message={message} members={members} />
113
- ))}
120
+ {thread.messages
121
+ .map((message) => message.target)
122
+ .filter(isNonNullable)
123
+ .map((message) => (
124
+ <MessageContainer key={message.id} message={message} members={members} />
125
+ ))}
114
126
  </div>
115
127
  {/* NOTE(thure): This can’t also be the `overflow-anchor` because `ScrollArea` injects an interceding node that contains this necessary ref’d element. */}
116
128
  <div role='none' className='bs-px -mbs-px' ref={threadScrollRef} />
@@ -5,6 +5,7 @@
5
5
  import { CheckCircle, X } from '@phosphor-icons/react';
6
6
  import React, { useCallback, useMemo, useRef, useState } from 'react';
7
7
 
8
+ import { RelationSourceId } from '@dxos/echo-schema';
8
9
  import { RefArray } from '@dxos/live-object';
9
10
  import { fullyQualifiedId, getSpace, useMembers } from '@dxos/react-client/echo';
10
11
  import { useIdentity } from '@dxos/react-client/halo';
@@ -17,14 +18,22 @@ import {
17
18
  hoverableFocusedWithinControls,
18
19
  mx,
19
20
  } from '@dxos/react-ui-theme';
20
- import { MessageTextbox, type MessageTextboxProps, Thread, ThreadFooter, ThreadHeading } from '@dxos/react-ui-thread';
21
+ import {
22
+ MessageTextbox,
23
+ type MessageTextboxProps,
24
+ Thread,
25
+ ThreadFooter,
26
+ ThreadHeading,
27
+ type ThreadProps,
28
+ } from '@dxos/react-ui-thread';
29
+ import { type AnchoredTo } from '@dxos/schema';
21
30
  import { isNonNullable } from '@dxos/util';
22
31
 
23
32
  import { MessageContainer } from './MessageContainer';
24
33
  import { command } from './command-extension';
25
- import { type ThreadContainerProps } from './types';
26
34
  import { useStatus } from '../hooks';
27
35
  import { THREAD_PLUGIN } from '../meta';
36
+ import { type ThreadType } from '../types';
28
37
  import { getMessageMetadata } from '../util';
29
38
 
30
39
  const sizeClass = getSize(4);
@@ -74,19 +83,29 @@ const DeleteThreadButton = ({ onDelete }: { onDelete: () => void }) => {
74
83
  );
75
84
  };
76
85
 
86
+ export type CommentContainerProps = {
87
+ anchor: AnchoredTo;
88
+ onAttend?: (anchor: AnchoredTo) => void;
89
+ onComment?: (anchor: AnchoredTo, message: string) => void;
90
+ onResolve?: (anchor: AnchoredTo) => void;
91
+ onMessageDelete?: (anchor: AnchoredTo, messageId: string) => void;
92
+ onThreadDelete?: (anchor: AnchoredTo) => void;
93
+ } & Pick<ThreadProps, 'current'>;
94
+
77
95
  export const CommentContainer = ({
78
- thread,
79
- detached,
96
+ anchor,
80
97
  current,
81
98
  onAttend,
82
99
  onComment,
83
100
  onResolve,
84
101
  onMessageDelete,
85
102
  onThreadDelete,
86
- }: ThreadContainerProps) => {
103
+ }: CommentContainerProps) => {
87
104
  const identity = useIdentity()!;
88
- const space = getSpace(thread);
105
+ const space = getSpace(anchor);
89
106
  const members = useMembers(space?.key);
107
+ const detached = !anchor.anchor;
108
+ const thread = anchor[RelationSourceId] as ThreadType;
90
109
  const activity = useStatus(space, fullyQualifiedId(thread));
91
110
  const { t } = useTranslation(THREAD_PLUGIN);
92
111
  const threadScrollRef = useRef<HTMLDivElement | null>(null);
@@ -111,23 +130,23 @@ export const CommentContainer = ({
111
130
  const scrollToEnd = (behavior: ScrollBehavior) =>
112
131
  setTimeout(() => threadScrollRef.current?.scrollIntoView({ behavior, block: 'end' }), 10);
113
132
 
114
- const handleAttend = useCallback(() => onAttend?.(thread), [onAttend, thread]);
115
- const handleResolve = useCallback(() => onResolve?.(thread), [onResolve, thread]);
116
- const handleMessageDelete = useCallback((id: string) => onMessageDelete?.(thread, id), [onMessageDelete, thread]);
117
- const handleThreadDelete = useCallback(() => onThreadDelete?.(thread), [onThreadDelete, thread]);
133
+ const handleAttend = useCallback(() => onAttend?.(anchor), [onAttend, anchor]);
134
+ const handleResolve = useCallback(() => onResolve?.(anchor), [onResolve, anchor]);
135
+ const handleMessageDelete = useCallback((id: string) => onMessageDelete?.(anchor, id), [onMessageDelete, anchor]);
136
+ const handleThreadDelete = useCallback(() => onThreadDelete?.(anchor), [onThreadDelete, anchor]);
118
137
 
119
138
  const handleComment: MessageTextboxProps['onSend'] = useCallback(() => {
120
139
  if (!messageRef.current) {
121
140
  return false;
122
141
  }
123
142
 
124
- onComment?.(thread, messageRef.current);
143
+ onComment?.(anchor, messageRef.current);
125
144
  messageRef.current = '';
126
145
  scrollToEnd('instant');
127
146
  rerenderEditor();
128
147
 
129
148
  return true;
130
- }, [thread, identity]);
149
+ }, [anchor, identity]);
131
150
 
132
151
  return (
133
152
  <Thread onClickCapture={handleAttend} onFocusCapture={handleAttend} current={current} id={fullyQualifiedId(thread)}>
@@ -5,50 +5,52 @@
5
5
  import '@dxos-theme';
6
6
 
7
7
  import { type Meta } from '@storybook/react';
8
- import React, { useEffect, useState } from 'react';
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
- import { ThreadType } from '@dxos/plugin-space/types';
12
+ import { Expando, Query, RelationSourceId, RelationTargetId } from '@dxos/echo-schema';
13
13
  import { faker } from '@dxos/random';
14
- import { Filter, fullyQualifiedId, useQuery, useSpace } from '@dxos/react-client/echo';
14
+ import { live, useQuery, useSpace } from '@dxos/react-client/echo';
15
15
  import { useIdentity } from '@dxos/react-client/halo';
16
16
  import { type ClientRepeatedComponentProps, ClientRepeater } from '@dxos/react-client/testing';
17
- import { DataType } from '@dxos/schema';
17
+ import { AnchoredTo, DataType } from '@dxos/schema';
18
18
  import { withLayout, withTheme } from '@dxos/storybook-utils';
19
19
 
20
20
  import { CommentsContainer } from './CommentsContainer';
21
21
  import { createCommentThread } from './testing';
22
22
  import translations from '../translations';
23
+ import { ThreadType } from '../types';
23
24
 
24
25
  faker.seed(1);
25
26
 
26
27
  const Story = ({ spaceKey }: ClientRepeatedComponentProps) => {
27
28
  const identity = useIdentity();
28
29
  const space = useSpace(spaceKey);
29
- const threads = useQuery(space, Filter.type(ThreadType));
30
- const [detached, setDetached] = useState<string[]>([]);
30
+ const anchors = useQuery(space, Query.type(AnchoredTo));
31
31
 
32
32
  useEffect(() => {
33
33
  if (identity && space) {
34
34
  const t = setTimeout(async () => {
35
- space.db.add(createCommentThread(identity));
36
- const thread = space.db.add(createCommentThread(identity));
37
- setDetached([fullyQualifiedId(thread)]);
35
+ const object = space.db.add(live(Expando, {}));
36
+ const thread1 = space.db.add(createCommentThread(identity));
37
+ const thread2 = space.db.add(createCommentThread(identity));
38
+ space.db.add(live(AnchoredTo, { [RelationSourceId]: thread1, [RelationTargetId]: object }));
39
+ space.db.add(live(AnchoredTo, { [RelationSourceId]: thread2, [RelationTargetId]: object }));
38
40
  });
39
41
 
40
42
  return () => clearTimeout(t);
41
43
  }
42
44
  }, [identity, space]);
43
45
 
44
- if (!identity || !space || !threads) {
46
+ if (!identity || !space || !anchors) {
45
47
  return null;
46
48
  }
47
49
 
48
50
  return (
49
51
  <div className='flex justify-center overflow-y-auto bg-white dark:bg-black'>
50
52
  <div className='flex flex-col w-[30rem]'>
51
- <CommentsContainer threads={threads} detached={detached} onThreadDelete={console.log} />
53
+ <CommentsContainer anchors={anchors} onThreadDelete={console.log} />
52
54
  </div>
53
55
  </div>
54
56
  );
@@ -5,21 +5,18 @@
5
5
  import { ChatText } from '@phosphor-icons/react';
6
6
  import React, { useEffect } from 'react';
7
7
 
8
- import { type ThreadType } from '@dxos/plugin-space/types';
8
+ import { RelationSourceId } from '@dxos/echo-schema';
9
9
  import { fullyQualifiedId } from '@dxos/react-client/echo';
10
10
  import { useTranslation, Trans } from '@dxos/react-ui';
11
11
  import { descriptionMessage, mx } from '@dxos/react-ui-theme';
12
+ import { type AnchoredTo } from '@dxos/schema';
12
13
 
13
- import { CommentContainer } from './CommentContainer';
14
- import { type ThreadContainerProps } from './types';
14
+ import { CommentContainer, type CommentContainerProps } from './CommentContainer';
15
15
  import { THREAD_PLUGIN } from '../meta';
16
+ import { type ThreadType } from '../types';
16
17
 
17
- export type ThreadsContainerProps = Omit<ThreadContainerProps, 'thread' | 'detached' | 'current' | 'autoFocus'> & {
18
- threads: ThreadType[];
19
- /**
20
- * Threads that are no longer anchored to a position in the object.
21
- */
22
- detached?: string[];
18
+ export type ThreadsContainerProps = Omit<CommentContainerProps, 'anchor' | 'current'> & {
19
+ anchors: AnchoredTo[];
23
20
  currentId?: string;
24
21
  showResolvedThreads?: boolean;
25
22
  };
@@ -27,15 +24,15 @@ export type ThreadsContainerProps = Omit<ThreadContainerProps, 'thread' | 'detac
27
24
  /**
28
25
  * Comment threads.
29
26
  */
30
- export const CommentsContainer = ({
31
- threads,
32
- detached = [],
33
- currentId,
34
- showResolvedThreads,
35
- ...props
36
- }: ThreadsContainerProps) => {
27
+ export const CommentsContainer = ({ anchors, currentId, showResolvedThreads, ...props }: ThreadsContainerProps) => {
37
28
  const { t } = useTranslation(THREAD_PLUGIN);
38
- const filteredThreads = showResolvedThreads ? threads : threads.filter((thread) => !(thread?.status === 'resolved'));
29
+ // TODO(wittjosiah): There seems to be a race between thread and anchor being deleted.
30
+ const filteredAnchors = showResolvedThreads
31
+ ? anchors.filter((anchor) => !!anchor[RelationSourceId])
32
+ : anchors.filter((anchor) => {
33
+ const thread = anchor[RelationSourceId];
34
+ return thread && thread.status !== 'resolved';
35
+ });
39
36
 
40
37
  useEffect(() => {
41
38
  if (currentId) {
@@ -45,18 +42,11 @@ export const CommentsContainer = ({
45
42
 
46
43
  return (
47
44
  <>
48
- {filteredThreads.length > 0 ? (
49
- filteredThreads.map((thread) => {
45
+ {filteredAnchors.length > 0 ? (
46
+ filteredAnchors.map((anchor) => {
47
+ const thread = anchor[RelationSourceId] as ThreadType;
50
48
  const threadId = fullyQualifiedId(thread);
51
- return (
52
- <CommentContainer
53
- key={threadId}
54
- thread={thread}
55
- current={currentId === threadId}
56
- detached={detached.includes(threadId)}
57
- {...props}
58
- />
59
- );
49
+ return <CommentContainer key={threadId} anchor={anchor} current={currentId === threadId} {...props} />;
60
50
  })
61
51
  ) : (
62
52
  <div role='alert' className={mx(descriptionMessage, 'place-self-center rounded-lg text-center m-4')}>