@stream-io/video-react-sdk 1.43.2 → 2.0.0-beta.1

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 (328) hide show
  1. package/CHANGELOG.md +18 -19
  2. package/dist/css/embedded.css +2592 -1498
  3. package/dist/css/embedded.css.map +1 -1
  4. package/dist/css/styles.css +2388 -1222
  5. package/dist/css/styles.css.map +1 -1
  6. package/dist/embedded.cjs.js +535 -476
  7. package/dist/embedded.cjs.js.map +1 -1
  8. package/dist/esm/index.js +10 -7
  9. package/dist/esm/index.js.map +1 -1
  10. package/dist/esm/src/components/Avatar/Avatar.js +13 -5
  11. package/dist/esm/src/components/Avatar/Avatar.js.map +1 -1
  12. package/dist/esm/src/components/Badge/Badge.js +21 -0
  13. package/dist/esm/src/components/Badge/Badge.js.map +1 -0
  14. package/dist/esm/src/components/Button/Button.js +10 -0
  15. package/dist/esm/src/components/Button/Button.js.map +1 -0
  16. package/dist/esm/src/components/Button/CompositeButton.js +10 -17
  17. package/dist/esm/src/components/Button/CompositeButton.js.map +1 -1
  18. package/dist/esm/src/components/Button/IconButton.js +3 -9
  19. package/dist/esm/src/components/Button/IconButton.js.map +1 -1
  20. package/dist/esm/src/components/CallControls/AcceptCallButton.js +3 -2
  21. package/dist/esm/src/components/CallControls/AcceptCallButton.js.map +1 -1
  22. package/dist/esm/src/components/CallControls/CallControls.js +3 -0
  23. package/dist/esm/src/components/CallControls/CallControls.js.map +1 -1
  24. package/dist/esm/src/components/CallControls/CancelCallButton.js +11 -6
  25. package/dist/esm/src/components/CallControls/CancelCallButton.js.map +1 -1
  26. package/dist/esm/src/components/CallControls/ReactionsButton.js +7 -3
  27. package/dist/esm/src/components/CallControls/ReactionsButton.js.map +1 -1
  28. package/dist/esm/src/components/CallControls/RecordCallButton.js +17 -11
  29. package/dist/esm/src/components/CallControls/RecordCallButton.js.map +1 -1
  30. package/dist/esm/src/components/CallControls/ScreenShareButton.js +11 -4
  31. package/dist/esm/src/components/CallControls/ScreenShareButton.js.map +1 -1
  32. package/dist/esm/src/components/CallControls/ToggleAudioButton.js +28 -17
  33. package/dist/esm/src/components/CallControls/ToggleAudioButton.js.map +1 -1
  34. package/dist/esm/src/components/CallControls/ToggleAudioOutputButton.js +9 -4
  35. package/dist/esm/src/components/CallControls/ToggleAudioOutputButton.js.map +1 -1
  36. package/dist/esm/src/components/CallControls/ToggleVideoButton.js +32 -23
  37. package/dist/esm/src/components/CallControls/ToggleVideoButton.js.map +1 -1
  38. package/dist/esm/src/components/CallParticipantsList/BlockedUserListing.js +3 -3
  39. package/dist/esm/src/components/CallParticipantsList/BlockedUserListing.js.map +1 -1
  40. package/dist/esm/src/components/CallParticipantsList/CallParticipantListHeader.js +8 -3
  41. package/dist/esm/src/components/CallParticipantsList/CallParticipantListHeader.js.map +1 -1
  42. package/dist/esm/src/components/CallParticipantsList/CallParticipantListingItem.js +20 -7
  43. package/dist/esm/src/components/CallParticipantsList/CallParticipantListingItem.js.map +1 -1
  44. package/dist/esm/src/components/CallParticipantsList/CallParticipantsList.js +8 -5
  45. package/dist/esm/src/components/CallParticipantsList/CallParticipantsList.js.map +1 -1
  46. package/dist/esm/src/components/CallParticipantsList/EmptyParticipantSearchList.js +5 -2
  47. package/dist/esm/src/components/CallParticipantsList/EmptyParticipantSearchList.js.map +1 -1
  48. package/dist/esm/src/components/CallRecordingList/CallRecordingListHeader.js +7 -3
  49. package/dist/esm/src/components/CallRecordingList/CallRecordingListHeader.js.map +1 -1
  50. package/dist/esm/src/components/DeviceSettings/DeviceAudioPreviewItem.js +1 -1
  51. package/dist/esm/src/components/DeviceSettings/DeviceAudioPreviewItem.js.map +1 -1
  52. package/dist/esm/src/components/DeviceSettings/DeviceSelector.js +1 -1
  53. package/dist/esm/src/components/DeviceSettings/DeviceSelector.js.map +1 -1
  54. package/dist/esm/src/components/DeviceSettings/DeviceSelectorAudio.js +2 -2
  55. package/dist/esm/src/components/DeviceSettings/DeviceSelectorAudio.js.map +1 -1
  56. package/dist/esm/src/components/DeviceSettings/DeviceSettings.js +8 -5
  57. package/dist/esm/src/components/DeviceSettings/DeviceSettings.js.map +1 -1
  58. package/dist/esm/src/components/DeviceSettings/SpeakerTest.js +10 -4
  59. package/dist/esm/src/components/DeviceSettings/SpeakerTest.js.map +1 -1
  60. package/dist/esm/src/components/DropdownSelect/DropdownSelect.js +1 -1
  61. package/dist/esm/src/components/DropdownSelect/DropdownSelect.js.map +1 -1
  62. package/dist/esm/src/components/Menu/GenericMenu.js +2 -1
  63. package/dist/esm/src/components/Menu/GenericMenu.js.map +1 -1
  64. package/dist/esm/src/components/Menu/MenuToggle.js +3 -0
  65. package/dist/esm/src/components/Menu/MenuToggle.js.map +1 -1
  66. package/dist/esm/src/components/Notification/MicCaptureErrorNotification.js +6 -3
  67. package/dist/esm/src/components/Notification/MicCaptureErrorNotification.js.map +1 -1
  68. package/dist/esm/src/components/Notification/Notification.js +12 -3
  69. package/dist/esm/src/components/Notification/Notification.js.map +1 -1
  70. package/dist/esm/src/components/Notification/PermissionNotification.js +2 -2
  71. package/dist/esm/src/components/Notification/PermissionNotification.js.map +1 -1
  72. package/dist/esm/src/components/Notification/RecordingInProgressNotification.js +7 -3
  73. package/dist/esm/src/components/Notification/RecordingInProgressNotification.js.map +1 -1
  74. package/dist/esm/src/components/Notification/SpeakingWhileMutedNotification.js +7 -2
  75. package/dist/esm/src/components/Notification/SpeakingWhileMutedNotification.js.map +1 -1
  76. package/dist/esm/src/components/Permissions/PermissionRequests.js +13 -12
  77. package/dist/esm/src/components/Permissions/PermissionRequests.js.map +1 -1
  78. package/dist/esm/src/components/RingingCall/RingingCall.js +38 -14
  79. package/dist/esm/src/components/RingingCall/RingingCall.js.map +1 -1
  80. package/dist/esm/src/components/RingingCall/RingingCallControls.js +7 -3
  81. package/dist/esm/src/components/RingingCall/RingingCallControls.js.map +1 -1
  82. package/dist/esm/src/components/Search/SearchInput.js +1 -1
  83. package/dist/esm/src/components/Search/SearchInput.js.map +1 -1
  84. package/dist/esm/src/components/StreamTheme/StreamTheme.js +2 -2
  85. package/dist/esm/src/components/StreamTheme/StreamTheme.js.map +1 -1
  86. package/dist/esm/src/components/Tooltip/Tooltip.js +8 -8
  87. package/dist/esm/src/components/Tooltip/Tooltip.js.map +1 -1
  88. package/dist/esm/src/components/VideoPreview/VideoPreview.js +36 -5
  89. package/dist/esm/src/components/VideoPreview/VideoPreview.js.map +1 -1
  90. package/dist/esm/src/core/components/CallLayout/LivestreamLayout.js +38 -12
  91. package/dist/esm/src/core/components/CallLayout/LivestreamLayout.js.map +1 -1
  92. package/dist/esm/src/core/components/CallLayout/PaginatedGridLayout.js +9 -5
  93. package/dist/esm/src/core/components/CallLayout/PaginatedGridLayout.js.map +1 -1
  94. package/dist/esm/src/core/components/CallLayout/PipLayout/Grid.js +9 -6
  95. package/dist/esm/src/core/components/CallLayout/PipLayout/Grid.js.map +1 -1
  96. package/dist/esm/src/core/components/CallLayout/PipLayout/Pip.js +9 -6
  97. package/dist/esm/src/core/components/CallLayout/PipLayout/Pip.js.map +1 -1
  98. package/dist/esm/src/core/components/CallLayout/SpeakerLayout.js +11 -6
  99. package/dist/esm/src/core/components/CallLayout/SpeakerLayout.js.map +1 -1
  100. package/dist/esm/src/core/components/ParticipantView/ConnectionQualityIndicator.js +25 -0
  101. package/dist/esm/src/core/components/ParticipantView/ConnectionQualityIndicator.js.map +1 -0
  102. package/dist/esm/src/core/components/ParticipantView/DefaultParticipantViewUI.js +17 -13
  103. package/dist/esm/src/core/components/ParticipantView/DefaultParticipantViewUI.js.map +1 -1
  104. package/dist/esm/src/core/components/ParticipantView/ParticipantActionsContextMenu.js +13 -8
  105. package/dist/esm/src/core/components/ParticipantView/ParticipantActionsContextMenu.js.map +1 -1
  106. package/dist/esm/src/core/components/StreamVideo/StreamVideo.js +24 -3
  107. package/dist/esm/src/core/components/StreamVideo/StreamVideo.js.map +1 -1
  108. package/dist/esm/src/core/components/Video/BaseVideoPlaceholder.js +3 -13
  109. package/dist/esm/src/core/components/Video/BaseVideoPlaceholder.js.map +1 -1
  110. package/dist/esm/src/core/components/Video/DefaultPictureInPicturePlaceholder.js +4 -2
  111. package/dist/esm/src/core/components/Video/DefaultPictureInPicturePlaceholder.js.map +1 -1
  112. package/dist/esm/src/core/components/Video/DefaultVideoPlaceholder.js +4 -2
  113. package/dist/esm/src/core/components/Video/DefaultVideoPlaceholder.js.map +1 -1
  114. package/dist/esm/src/embedded/EmbeddedClientProvider.js +7 -4
  115. package/dist/esm/src/embedded/EmbeddedClientProvider.js.map +1 -1
  116. package/dist/esm/src/embedded/call/CallControls.js +10 -6
  117. package/dist/esm/src/embedded/call/CallControls.js.map +1 -1
  118. package/dist/esm/src/embedded/call/CallHeader.js +10 -7
  119. package/dist/esm/src/embedded/call/CallHeader.js.map +1 -1
  120. package/dist/esm/src/embedded/call/CallLayout.js +8 -5
  121. package/dist/esm/src/embedded/call/CallLayout.js.map +1 -1
  122. package/dist/esm/src/embedded/call/CallStateRouter.js +7 -4
  123. package/dist/esm/src/embedded/call/CallStateRouter.js.map +1 -1
  124. package/dist/esm/src/embedded/hooks/useLayout.js +7 -4
  125. package/dist/esm/src/embedded/hooks/useLayout.js.map +1 -1
  126. package/dist/esm/src/embedded/livestream/host/HostLayout.js +12 -7
  127. package/dist/esm/src/embedded/livestream/host/HostLayout.js.map +1 -1
  128. package/dist/esm/src/embedded/livestream/host/HostStateRouter.js +12 -7
  129. package/dist/esm/src/embedded/livestream/host/HostStateRouter.js.map +1 -1
  130. package/dist/esm/src/embedded/livestream/viewer/ViewerLayout.js +9 -6
  131. package/dist/esm/src/embedded/livestream/viewer/ViewerLayout.js.map +1 -1
  132. package/dist/esm/src/embedded/livestream/viewer/ViewerLobby.js +12 -9
  133. package/dist/esm/src/embedded/livestream/viewer/ViewerLobby.js.map +1 -1
  134. package/dist/esm/src/embedded/livestream/viewer/ViewerStateRouter.js +7 -4
  135. package/dist/esm/src/embedded/livestream/viewer/ViewerStateRouter.js.map +1 -1
  136. package/dist/esm/src/embedded/shared/BlurToggleButton/BlurToggleButton.js +13 -9
  137. package/dist/esm/src/embedded/shared/BlurToggleButton/BlurToggleButton.js.map +1 -1
  138. package/dist/esm/src/embedded/shared/CallDuration/CallDuration.js +40 -0
  139. package/dist/esm/src/embedded/shared/CallDuration/CallDuration.js.map +1 -0
  140. package/dist/esm/src/embedded/shared/CallFeedback/CallEndedScreen.js +8 -6
  141. package/dist/esm/src/embedded/shared/CallFeedback/CallEndedScreen.js.map +1 -1
  142. package/dist/esm/src/embedded/shared/CallFeedback/RatingScreen.js +26 -2
  143. package/dist/esm/src/embedded/shared/CallFeedback/RatingScreen.js.map +1 -1
  144. package/dist/esm/src/embedded/shared/CallFeedback/StarRating.js +12 -6
  145. package/dist/esm/src/embedded/shared/CallFeedback/StarRating.js.map +1 -1
  146. package/dist/esm/src/embedded/shared/CallFeedback/ThankYouScreen.js +8 -6
  147. package/dist/esm/src/embedded/shared/CallFeedback/ThankYouScreen.js.map +1 -1
  148. package/dist/esm/src/embedded/shared/ConnectionNotification/ConnectionNotification.js +15 -14
  149. package/dist/esm/src/embedded/shared/ConnectionNotification/ConnectionNotification.js.map +1 -1
  150. package/dist/esm/src/embedded/shared/EmbeddedParticipantViewUI/EmbeddedParticipantViewUI.js +4 -0
  151. package/dist/esm/src/embedded/shared/EmbeddedParticipantViewUI/EmbeddedParticipantViewUI.js.map +1 -1
  152. package/dist/esm/src/embedded/shared/JoinError/JoinError.js +8 -6
  153. package/dist/esm/src/embedded/shared/JoinError/JoinError.js.map +1 -1
  154. package/dist/esm/src/embedded/shared/Lobby/DeviceControls.js +11 -7
  155. package/dist/esm/src/embedded/shared/Lobby/DeviceControls.js.map +1 -1
  156. package/dist/esm/src/embedded/shared/Lobby/DisabledDeviceButton.js +6 -4
  157. package/dist/esm/src/embedded/shared/Lobby/DisabledDeviceButton.js.map +1 -1
  158. package/dist/esm/src/embedded/shared/Lobby/Lobby.js +10 -9
  159. package/dist/esm/src/embedded/shared/Lobby/Lobby.js.map +1 -1
  160. package/dist/esm/src/embedded/shared/Lobby/ToggleCameraButton.js +6 -4
  161. package/dist/esm/src/embedded/shared/Lobby/ToggleCameraButton.js.map +1 -1
  162. package/dist/esm/src/embedded/shared/Lobby/ToggleMicButton.js +8 -6
  163. package/dist/esm/src/embedded/shared/Lobby/ToggleMicButton.js.map +1 -1
  164. package/dist/esm/src/embedded/shared/Lobby/VideoPreviewFallbacks.js +11 -9
  165. package/dist/esm/src/embedded/shared/Lobby/VideoPreviewFallbacks.js.map +1 -1
  166. package/dist/esm/src/embedded/shared/ViewersCount/ViewersCount.js +6 -4
  167. package/dist/esm/src/embedded/shared/ViewersCount/ViewersCount.js.map +1 -1
  168. package/dist/esm/src/hooks/useDeviceList.js +4 -2
  169. package/dist/esm/src/hooks/useDeviceList.js.map +1 -1
  170. package/dist/esm/src/i18n/Streami18n.js +58 -0
  171. package/dist/esm/src/i18n/Streami18n.js.map +1 -0
  172. package/dist/esm/src/i18n/TranslationContext.js +42 -0
  173. package/dist/esm/src/i18n/TranslationContext.js.map +1 -0
  174. package/dist/esm/src/i18n/runtimeDefaults.js +20 -0
  175. package/dist/esm/src/i18n/runtimeDefaults.js.map +1 -0
  176. package/dist/esm/src/i18n/useStreami18n.js +49 -0
  177. package/dist/esm/src/i18n/useStreami18n.js.map +1 -0
  178. package/dist/esm/src/wrappers/LivestreamPlayer/LivestreamPlayer.js +4 -0
  179. package/dist/esm/src/wrappers/LivestreamPlayer/LivestreamPlayer.js.map +1 -1
  180. package/dist/index.cjs.js +559 -623
  181. package/dist/index.cjs.js.map +1 -1
  182. package/dist/index.d.ts +1 -1
  183. package/dist/src/components/Avatar/Avatar.d.ts +9 -4
  184. package/dist/src/components/Badge/Badge.d.ts +23 -0
  185. package/dist/src/components/Badge/index.d.ts +1 -0
  186. package/dist/src/components/Button/Button.d.ts +16 -0
  187. package/dist/src/components/Button/CompositeButton.d.ts +6 -3
  188. package/dist/src/components/Button/IconButton.d.ts +7 -7
  189. package/dist/src/components/Button/index.d.ts +2 -2
  190. package/dist/src/components/CallControls/CancelCallButton.d.ts +3 -1
  191. package/dist/src/components/CallControls/ToggleAudioButton.d.ts +3 -3
  192. package/dist/src/components/CallControls/ToggleAudioOutputButton.d.ts +2 -2
  193. package/dist/src/components/CallControls/ToggleVideoButton.d.ts +3 -3
  194. package/dist/src/components/CallControls/index.d.ts +0 -1
  195. package/dist/src/components/Menu/GenericMenu.d.ts +1 -0
  196. package/dist/src/components/Notification/Notification.d.ts +2 -1
  197. package/dist/src/components/StreamTheme/StreamTheme.d.ts +2 -1
  198. package/dist/src/components/VideoPreview/VideoPreview.d.ts +6 -1
  199. package/dist/src/components/index.d.ts +1 -1
  200. package/dist/src/core/components/ParticipantView/ConnectionQualityIndicator.d.ts +10 -0
  201. package/dist/src/core/components/ParticipantView/index.d.ts +1 -0
  202. package/dist/src/core/components/StreamVideo/StreamVideo.d.ts +18 -2
  203. package/dist/src/embedded/shared/CallDuration/CallDuration.d.ts +9 -0
  204. package/dist/src/embedded/shared/index.d.ts +1 -0
  205. package/dist/src/i18n/Streami18n.d.ts +56 -0
  206. package/dist/src/i18n/TranslationContext.d.ts +30 -0
  207. package/dist/src/i18n/index.d.ts +16 -0
  208. package/dist/src/i18n/keys.d.ts +164 -0
  209. package/dist/src/i18n/runtimeDefaults.d.ts +17 -0
  210. package/dist/src/i18n/types.d.ts +45 -0
  211. package/dist/src/i18n/useStreami18n.d.ts +19 -0
  212. package/index.ts +1 -1
  213. package/package.json +18 -13
  214. package/src/components/Avatar/Avatar.tsx +53 -19
  215. package/src/components/Badge/Badge.tsx +48 -0
  216. package/src/components/Badge/index.ts +1 -0
  217. package/src/components/Button/Button.tsx +49 -0
  218. package/src/components/Button/CompositeButton.tsx +82 -73
  219. package/src/components/Button/IconButton.tsx +19 -29
  220. package/src/components/Button/index.ts +2 -2
  221. package/src/components/CallControls/AcceptCallButton.tsx +3 -1
  222. package/src/components/CallControls/CancelCallButton.tsx +32 -24
  223. package/src/components/CallControls/ReactionsButton.tsx +7 -3
  224. package/src/components/CallControls/RecordCallButton.tsx +50 -23
  225. package/src/components/CallControls/ScreenShareButton.tsx +27 -6
  226. package/src/components/CallControls/ToggleAudioButton.tsx +62 -61
  227. package/src/components/CallControls/ToggleAudioOutputButton.tsx +7 -4
  228. package/src/components/CallControls/ToggleVideoButton.tsx +66 -66
  229. package/src/components/CallControls/index.ts +0 -1
  230. package/src/components/CallParticipantsList/BlockedUserListing.tsx +9 -2
  231. package/src/components/CallParticipantsList/CallParticipantListHeader.tsx +10 -3
  232. package/src/components/CallParticipantsList/CallParticipantListingItem.tsx +33 -8
  233. package/src/components/CallParticipantsList/CallParticipantsList.tsx +21 -5
  234. package/src/components/CallParticipantsList/EmptyParticipantSearchList.tsx +2 -2
  235. package/src/components/CallRecordingList/CallRecordingListHeader.tsx +11 -3
  236. package/src/components/DeviceSettings/DeviceAudioPreviewItem.tsx +3 -1
  237. package/src/components/DeviceSettings/DeviceSelector.tsx +1 -1
  238. package/src/components/DeviceSettings/DeviceSelectorAudio.tsx +2 -7
  239. package/src/components/DeviceSettings/DeviceSettings.tsx +14 -5
  240. package/src/components/DeviceSettings/SpeakerTest.tsx +7 -2
  241. package/src/components/DropdownSelect/DropdownSelect.tsx +3 -1
  242. package/src/components/Menu/GenericMenu.tsx +4 -0
  243. package/src/components/Notification/MicCaptureErrorNotification.tsx +7 -2
  244. package/src/components/Notification/Notification.tsx +20 -4
  245. package/src/components/Notification/PermissionNotification.tsx +2 -0
  246. package/src/components/Notification/RecordingInProgressNotification.tsx +5 -6
  247. package/src/components/Notification/SpeakingWhileMutedNotification.tsx +8 -2
  248. package/src/components/Permissions/PermissionRequests.tsx +50 -43
  249. package/src/components/RingingCall/RingingCall.tsx +40 -14
  250. package/src/components/RingingCall/RingingCallControls.tsx +2 -1
  251. package/src/components/Search/SearchInput.tsx +2 -3
  252. package/src/components/StreamTheme/StreamTheme.tsx +3 -1
  253. package/src/components/Tooltip/Tooltip.tsx +3 -10
  254. package/src/components/VideoPreview/VideoPreview.tsx +50 -5
  255. package/src/components/index.ts +1 -1
  256. package/src/core/components/CallLayout/LivestreamLayout.tsx +48 -18
  257. package/src/core/components/CallLayout/PaginatedGridLayout.tsx +14 -0
  258. package/src/core/components/CallLayout/PipLayout/Grid.tsx +10 -2
  259. package/src/core/components/CallLayout/PipLayout/Pip.tsx +6 -2
  260. package/src/core/components/CallLayout/SpeakerLayout.tsx +27 -0
  261. package/src/core/components/CallLayout/partcipantFilter.test.ts +38 -31
  262. package/src/core/components/ParticipantView/ConnectionQualityIndicator.tsx +54 -0
  263. package/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx +60 -27
  264. package/src/core/components/ParticipantView/ParticipantActionsContextMenu.tsx +63 -22
  265. package/src/core/components/ParticipantView/index.ts +1 -0
  266. package/src/core/components/StreamVideo/StreamVideo.tsx +39 -4
  267. package/src/core/components/Video/BaseVideoPlaceholder.tsx +13 -30
  268. package/src/core/components/Video/DefaultPictureInPicturePlaceholder.tsx +5 -2
  269. package/src/core/components/Video/DefaultVideoPlaceholder.tsx +2 -2
  270. package/src/embedded/call/CallControls.tsx +9 -18
  271. package/src/embedded/call/CallHeader.tsx +3 -12
  272. package/src/embedded/call/CallLayout.tsx +1 -1
  273. package/src/embedded/livestream/host/HostLayout.tsx +26 -20
  274. package/src/embedded/livestream/host/HostStateRouter.tsx +12 -8
  275. package/src/embedded/livestream/viewer/ViewerLayout.tsx +8 -11
  276. package/src/embedded/livestream/viewer/ViewerLobby.tsx +31 -15
  277. package/src/embedded/shared/BlurToggleButton/BlurToggleButton.tsx +18 -12
  278. package/src/embedded/shared/CallDuration/CallDuration.tsx +32 -0
  279. package/src/embedded/shared/CallFeedback/CallEndedScreen.tsx +27 -13
  280. package/src/embedded/shared/CallFeedback/RatingScreen.tsx +20 -12
  281. package/src/embedded/shared/CallFeedback/StarRating.tsx +10 -3
  282. package/src/embedded/shared/CallFeedback/ThankYouScreen.tsx +6 -3
  283. package/src/embedded/shared/ConnectionNotification/ConnectionNotification.tsx +21 -14
  284. package/src/embedded/shared/JoinError/JoinError.tsx +7 -6
  285. package/src/embedded/shared/Lobby/DeviceControls.tsx +25 -3
  286. package/src/embedded/shared/Lobby/Lobby.tsx +19 -22
  287. package/src/embedded/shared/Lobby/ToggleMicButton.tsx +10 -3
  288. package/src/embedded/shared/Lobby/VideoPreviewFallbacks.tsx +4 -2
  289. package/src/embedded/shared/index.ts +1 -0
  290. package/src/hooks/useDeviceList.tsx +2 -2
  291. package/src/i18n/Streami18n.ts +67 -0
  292. package/src/i18n/TranslationContext.tsx +55 -0
  293. package/src/i18n/index.ts +22 -0
  294. package/src/i18n/keys.ts +169 -0
  295. package/src/i18n/runtimeDefaults.ts +17 -0
  296. package/src/i18n/types.ts +78 -0
  297. package/src/i18n/useStreami18n.ts +66 -0
  298. package/src/utilities/filter.test.ts +132 -124
  299. package/src/utilities/normalizeString.test.ts +50 -48
  300. package/dist/embedded-CallStatsLatencyChart-CpL1M_s0.cjs.js +0 -59
  301. package/dist/embedded-CallStatsLatencyChart-CpL1M_s0.cjs.js.map +0 -1
  302. package/dist/esm/src/components/Button/TextButton.js +0 -8
  303. package/dist/esm/src/components/Button/TextButton.js.map +0 -1
  304. package/dist/esm/src/components/CallControls/CallStatsButton.js +0 -18
  305. package/dist/esm/src/components/CallControls/CallStatsButton.js.map +0 -1
  306. package/dist/esm/src/components/CallStats/CallStats.js +0 -180
  307. package/dist/esm/src/components/CallStats/CallStats.js.map +0 -1
  308. package/dist/esm/src/components/CallStats/CallStatsLatencyChart.js +0 -57
  309. package/dist/esm/src/components/CallStats/CallStatsLatencyChart.js.map +0 -1
  310. package/dist/esm/src/translations/en.json.js +0 -177
  311. package/dist/esm/src/translations/en.json.js.map +0 -1
  312. package/dist/esm/src/translations/index.js +0 -6
  313. package/dist/esm/src/translations/index.js.map +0 -1
  314. package/dist/latency-chart-CpL1M_s0.cjs.js +0 -59
  315. package/dist/latency-chart-CpL1M_s0.cjs.js.map +0 -1
  316. package/dist/src/components/Button/TextButton.d.ts +0 -2
  317. package/dist/src/components/CallControls/CallStatsButton.d.ts +0 -4
  318. package/dist/src/components/CallStats/CallStats.d.ts +0 -22
  319. package/dist/src/components/CallStats/CallStatsLatencyChart.d.ts +0 -7
  320. package/dist/src/components/CallStats/index.d.ts +0 -1
  321. package/dist/src/translations/index.d.ts +0 -146
  322. package/src/components/Button/TextButton.tsx +0 -12
  323. package/src/components/CallControls/CallStatsButton.tsx +0 -37
  324. package/src/components/CallStats/CallStats.tsx +0 -439
  325. package/src/components/CallStats/CallStatsLatencyChart.tsx +0 -76
  326. package/src/components/CallStats/index.ts +0 -1
  327. package/src/translations/en.json +0 -154
  328. package/src/translations/index.ts +0 -3
@@ -6,14 +6,12 @@ import {
6
6
  useEffect,
7
7
  useState,
8
8
  } from 'react';
9
- import {
10
- useCall,
11
- useCallStateHooks,
12
- useI18n,
13
- } from '@stream-io/video-react-bindings';
9
+ import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
10
+ import { useI18n } from '../../../i18n';
14
11
  import { hasScreenShare, humanize } from '@stream-io/video-client';
15
12
  import { ParticipantView, useParticipantViewContext } from '../ParticipantView';
16
13
  import { ParticipantsAudio } from '../Audio';
14
+ import { Icon, IconButton } from '../../../components';
17
15
  import {
18
16
  usePaginatedLayoutSortPreset,
19
17
  useRawRemoteParticipants,
@@ -218,21 +216,40 @@ export const BackstageLayout = (props: BackstageLayoutProps) => {
218
216
  {startsAt && (
219
217
  <span className="str-video__livestream-layout__starts-at">
220
218
  {startsAtPassed
221
- ? t('Livestream starts soon')
222
- : t('Livestream starts at {{ time }}', {
223
- time: startsAt.toLocaleTimeString([], {
224
- hour: '2-digit',
225
- minute: '2-digit',
226
- }),
227
- })}
219
+ ? t(
220
+ 'livestream.backstage.startsSoon.text',
221
+ 'Livestream starts soon',
222
+ )
223
+ : t(
224
+ 'livestream.backstage.startsAt.text',
225
+ 'Livestream starts at {{ time }}',
226
+ {
227
+ time: startsAt.toLocaleTimeString([], {
228
+ hour: '2-digit',
229
+ minute: '2-digit',
230
+ }),
231
+ },
232
+ )}
228
233
  </span>
229
234
  )}
230
235
  {showEarlyParticipantCount && (
231
236
  <span className="str-video__livestream-layout__early-viewers-count">
232
- {t('{{ count }} participants joined early', {
233
- count: humanizeParticipantCount
237
+ <Icon icon="livestream-viewers" />
238
+ {/*
239
+ `count` stays the raw number so i18next can pick a plural form;
240
+ `formattedCount` carries the (possibly humanized) display string.
241
+ Behaviour change: with humanizing on, a count of 1 now renders the
242
+ singular - previously the humanized string defeated plural
243
+ selection and `_other` always won.
244
+ */}
245
+ {t('livestream.backstage.participantsJoinedEarly.text', {
246
+ count: participantCount,
247
+ formattedCount: humanizeParticipantCount
234
248
  ? humanize(participantCount)
235
249
  : participantCount,
250
+ defaultValue_one: '{{ formattedCount }} participant joined early',
251
+ defaultValue_other:
252
+ '{{ formattedCount }} participants joined early',
236
253
  })}
237
254
  </span>
238
255
  )}
@@ -283,11 +300,16 @@ const ParticipantOverlay = (props: {
283
300
  <div className="str-video__livestream-layout__overlay__bar-left">
284
301
  {showLiveBadge && (
285
302
  <span className="str-video__livestream-layout__live-badge">
286
- {t('Live')}
303
+ <span
304
+ className="str-video__livestream-layout__live-badge__dot"
305
+ aria-hidden="true"
306
+ />
307
+ {t('common.live.label', 'Live')}
287
308
  </span>
288
309
  )}
289
310
  {showParticipantCount && (
290
311
  <span className="str-video__livestream-layout__viewers-count">
312
+ <Icon icon="livestream-viewers" />
291
313
  {humanizeParticipantCount
292
314
  ? humanize(participantCount)
293
315
  : participantCount}
@@ -298,7 +320,7 @@ const ParticipantOverlay = (props: {
298
320
  className="str-video__livestream-layout__speaker-name"
299
321
  title={participant.name || participant.userId || ''}
300
322
  >
301
- {participant.name || participant.userId || ''}
323
+ <span>{participant.name || participant.userId || ''}</span>
302
324
  </span>
303
325
  )}
304
326
  </div>
@@ -311,7 +333,11 @@ const ParticipantOverlay = (props: {
311
333
  </div>
312
334
  <div className="str-video__livestream-layout__overlay__bar-right">
313
335
  {showMuteButton && (
314
- <span
336
+ <IconButton
337
+ icon={isSpeakerMuted ? 'speaker-off' : 'speaker'}
338
+ variant="secondary"
339
+ appearance="solid"
340
+ size="sm"
315
341
  className={clsx(
316
342
  'str-video__livestream-layout__mute-button',
317
343
  isSpeakerMuted &&
@@ -324,7 +350,11 @@ const ParticipantOverlay = (props: {
324
350
  participantViewElement &&
325
351
  typeof participantViewElement.requestFullscreen !==
326
352
  'undefined' && (
327
- <span
353
+ <IconButton
354
+ icon="fullscreen"
355
+ variant="secondary"
356
+ appearance="solid"
357
+ size="sm"
328
358
  className="str-video__livestream-layout__go-fullscreen"
329
359
  onClick={toggleFullScreen}
330
360
  />
@@ -1,5 +1,6 @@
1
1
  import { useEffect, useMemo, useState } from 'react';
2
2
  import { useCall } from '@stream-io/video-react-bindings';
3
+ import { useI18n } from '../../../i18n';
3
4
  import { StreamVideoParticipant } from '@stream-io/video-client';
4
5
  import clsx from 'clsx';
5
6
 
@@ -119,6 +120,7 @@ export type PaginatedGridLayoutProps = {
119
120
  >;
120
121
 
121
122
  export const PaginatedGridLayout = (props: PaginatedGridLayoutProps) => {
123
+ const { t } = useI18n();
122
124
  const {
123
125
  groupSize = (props.groupSize || 0) > 0
124
126
  ? props.groupSize || GROUP_SIZE
@@ -184,7 +186,13 @@ export const PaginatedGridLayout = (props: PaginatedGridLayoutProps) => {
184
186
  <div className="str-video__paginated-grid-layout">
185
187
  {pageArrowsVisible && pageCount > 1 && (
186
188
  <IconButton
189
+ size="sm"
190
+ variant="secondary"
187
191
  icon="caret-left"
192
+ aria-label={t(
193
+ 'callLayout.paginatedGridLayout.previousPage.ariaLabel',
194
+ 'Previous page',
195
+ )}
188
196
  disabled={page === 0}
189
197
  onClick={() =>
190
198
  setPage((currentPage) => Math.max(0, currentPage - 1))
@@ -202,8 +210,14 @@ export const PaginatedGridLayout = (props: PaginatedGridLayoutProps) => {
202
210
  )}
203
211
  {pageArrowsVisible && pageCount > 1 && (
204
212
  <IconButton
213
+ size="sm"
214
+ variant="secondary"
205
215
  disabled={page === pageCount - 1}
206
216
  icon="caret-right"
217
+ aria-label={t(
218
+ 'callLayout.paginatedGridLayout.nextPage.ariaLabel',
219
+ 'Next page',
220
+ )}
207
221
  onClick={() =>
208
222
  setPage((currentPage) => Math.min(pageCount - 1, currentPage + 1))
209
223
  }
@@ -1,4 +1,5 @@
1
- import { useCall, useI18n } from '@stream-io/video-react-bindings';
1
+ import { useCall } from '@stream-io/video-react-bindings';
2
+ import { useI18n } from '../../../../i18n';
2
3
  import { useEffect, useMemo, useState } from 'react';
3
4
  import clsx from 'clsx';
4
5
  import { hasScreenShare } from '@stream-io/video-client';
@@ -99,7 +100,10 @@ export const Grid = (props: PipLayoutGridProps) => {
99
100
  <div className="str-video__pip-screen-share-local">
100
101
  <Icon icon="screen-share-off" />
101
102
  <span className="str-video__pip-screen-share-local__title">
102
- {t('You are presenting your screen')}
103
+ {t(
104
+ 'common.presentingYourScreen.text',
105
+ 'You are presenting your screen',
106
+ )}
103
107
  </span>
104
108
  </div>
105
109
  ) : (
@@ -116,6 +120,8 @@ export const Grid = (props: PipLayoutGridProps) => {
116
120
  {pageArrowsVisible && page > 0 && (
117
121
  <IconButton
118
122
  icon="caret-left"
123
+ size="sm"
124
+ variant="secondary"
119
125
  onClick={() =>
120
126
  setPage((currentPage) => Math.max(0, currentPage - 1))
121
127
  }
@@ -144,6 +150,8 @@ export const Grid = (props: PipLayoutGridProps) => {
144
150
  {pageArrowsVisible && page < pageCount - 1 && (
145
151
  <IconButton
146
152
  icon="caret-right"
153
+ size="sm"
154
+ variant="secondary"
147
155
  onClick={() =>
148
156
  setPage((currentPage) => Math.min(pageCount - 1, currentPage + 1))
149
157
  }
@@ -1,4 +1,5 @@
1
- import { useCall, useI18n } from '@stream-io/video-react-bindings';
1
+ import { useCall } from '@stream-io/video-react-bindings';
2
+ import { useI18n } from '../../../../i18n';
2
3
  import { useEffect, useState } from 'react';
3
4
 
4
5
  import { hasScreenShare } from '@stream-io/video-client';
@@ -86,7 +87,10 @@ export const Pip = (props: PipLayoutProps) => {
86
87
  <div className="str-video__pip-screen-share-local">
87
88
  <Icon icon="screen-share-off" />
88
89
  <span className="str-video__pip-screen-share-local__title">
89
- {t('You are presenting your screen')}
90
+ {t(
91
+ 'common.presentingYourScreen.text',
92
+ 'You are presenting your screen',
93
+ )}
90
94
  </span>
91
95
  </div>
92
96
  ) : (
@@ -6,6 +6,7 @@ import {
6
6
  useCallStateHooks,
7
7
  useSpeakerLayoutSortPreset,
8
8
  } from '@stream-io/video-react-bindings';
9
+ import { useI18n } from '../../../i18n';
9
10
 
10
11
  import {
11
12
  DefaultParticipantViewUI,
@@ -282,6 +283,7 @@ type ScrollButtonsProps<T extends HTMLElement> = {
282
283
  const HorizontalScrollButtons = <T extends HTMLElement>({
283
284
  scrollWrapper,
284
285
  }: ScrollButtonsProps<T>) => {
286
+ const { t } = useI18n();
285
287
  const scrollPosition = useHorizontalScrollPosition(scrollWrapper);
286
288
 
287
289
  const scrollStartClickHandler = () => {
@@ -295,15 +297,27 @@ const HorizontalScrollButtons = <T extends HTMLElement>({
295
297
  <>
296
298
  {scrollPosition && scrollPosition !== 'start' && (
297
299
  <IconButton
300
+ size="sm"
301
+ variant="secondary"
298
302
  onClick={scrollStartClickHandler}
299
303
  icon="caret-left"
304
+ aria-label={t(
305
+ 'callLayout.speakerLayout.scrollParticipantsLeft.ariaLabel',
306
+ 'Scroll participants left',
307
+ )}
300
308
  className="str-video__speaker-layout__participants-bar--button-left"
301
309
  />
302
310
  )}
303
311
  {scrollPosition && scrollPosition !== 'end' && (
304
312
  <IconButton
313
+ size="sm"
314
+ variant="secondary"
305
315
  onClick={scrollEndClickHandler}
306
316
  icon="caret-right"
317
+ aria-label={t(
318
+ 'callLayout.speakerLayout.scrollParticipantsRight.ariaLabel',
319
+ 'Scroll participants right',
320
+ )}
307
321
  className="str-video__speaker-layout__participants-bar--button-right"
308
322
  />
309
323
  )}
@@ -314,6 +328,7 @@ const HorizontalScrollButtons = <T extends HTMLElement>({
314
328
  const VerticalScrollButtons = <T extends HTMLElement>({
315
329
  scrollWrapper,
316
330
  }: ScrollButtonsProps<T>) => {
331
+ const { t } = useI18n();
317
332
  const scrollPosition = useVerticalScrollPosition(scrollWrapper);
318
333
 
319
334
  const scrollTopClickHandler = () => {
@@ -327,15 +342,27 @@ const VerticalScrollButtons = <T extends HTMLElement>({
327
342
  <>
328
343
  {scrollPosition && scrollPosition !== 'top' && (
329
344
  <IconButton
345
+ size="sm"
346
+ variant="secondary"
330
347
  onClick={scrollTopClickHandler}
331
348
  icon="caret-up"
349
+ aria-label={t(
350
+ 'callLayout.speakerLayout.scrollParticipantsUp.ariaLabel',
351
+ 'Scroll participants up',
352
+ )}
332
353
  className="str-video__speaker-layout__participants-bar--button-top"
333
354
  />
334
355
  )}
335
356
  {scrollPosition && scrollPosition !== 'bottom' && (
336
357
  <IconButton
358
+ size="sm"
359
+ variant="secondary"
337
360
  onClick={scrollBottomClickHandler}
338
361
  icon="caret-down"
362
+ aria-label={t(
363
+ 'callLayout.speakerLayout.scrollParticipantsDown.ariaLabel',
364
+ 'Scroll participants down',
365
+ )}
339
366
  className="str-video__speaker-layout__participants-bar--button-bottom"
340
367
  />
341
368
  )}
@@ -1,7 +1,9 @@
1
1
  import { StreamVideoParticipant } from '@stream-io/video-client';
2
- import { test, type TestContext } from 'node:test';
2
+ import { describe, expect, it } from 'vitest';
3
3
  import { applyParticipantsFilter } from './hooks';
4
4
 
5
+ // `publishedTracks` is required: the filter-object path derives `hasVideo` / `hasAudio` /
6
+ // `hasScreenShare` from it, and those read the array unguarded.
5
7
  const participants = [
6
8
  {
7
9
  userId: 'host-id',
@@ -9,6 +11,7 @@ const participants = [
9
11
  isDominantSpeaker: true,
10
12
  name: 'Host',
11
13
  roles: ['host', 'admin'],
14
+ publishedTracks: [],
12
15
  },
13
16
  {
14
17
  userId: 'listener-id-1',
@@ -17,6 +20,7 @@ const participants = [
17
20
  name: 'Listener 1',
18
21
  roles: ['listener', 'user'],
19
22
  pin: { pinnedAt: new Date() },
23
+ publishedTracks: [],
20
24
  },
21
25
  {
22
26
  userId: 'listener-id-2',
@@ -24,42 +28,45 @@ const participants = [
24
28
  isDominantSpeaker: false,
25
29
  name: 'Listener 2',
26
30
  roles: ['listener', 'user'],
31
+ publishedTracks: [],
27
32
  },
28
- ] as StreamVideoParticipant[];
33
+ ] as unknown as StreamVideoParticipant[];
29
34
 
30
- test('applies predicate filter', (t: TestContext) => {
31
- const filtered = applyParticipantsFilter(participants, (p) =>
32
- p.roles.includes('listener'),
33
- );
35
+ describe('applyParticipantsFilter', () => {
36
+ it('applies predicate filter', () => {
37
+ const filtered = applyParticipantsFilter(participants, (p) =>
38
+ p.roles.includes('listener'),
39
+ );
34
40
 
35
- t.assert.strictEqual(filtered.length, 2);
36
- t.assert.deepStrictEqual(
37
- filtered.map((p) => p.userId),
38
- ['listener-id-1', 'listener-id-2'],
39
- );
40
- });
41
-
42
- test('applies filter object', (t: TestContext) => {
43
- const filtered = applyParticipantsFilter(participants, {
44
- $and: [
45
- { roles: { $contains: 'listener' } },
46
- { $not: { roles: { $contains: 'host' } } },
47
- ],
41
+ expect(filtered).toHaveLength(2);
42
+ expect(filtered.map((p) => p.userId)).toEqual([
43
+ 'listener-id-1',
44
+ 'listener-id-2',
45
+ ]);
48
46
  });
49
47
 
50
- t.assert.strictEqual(filtered.length, 2);
51
- t.assert.deepStrictEqual(
52
- filtered.map((p) => p.userId),
53
- ['listener-id-1', 'listener-id-2'],
54
- );
55
- });
48
+ it('applies filter object', () => {
49
+ const filtered = applyParticipantsFilter(participants, {
50
+ $and: [
51
+ { roles: { $contains: 'listener' } },
52
+ { $not: { roles: { $contains: 'host' } } },
53
+ ],
54
+ });
56
55
 
57
- test('filter object supports boolean pin property', (t: TestContext) => {
58
- const filtered = applyParticipantsFilter(participants, {
59
- roles: { $contains: 'listener' },
60
- isPinned: true,
56
+ expect(filtered).toHaveLength(2);
57
+ expect(filtered.map((p) => p.userId)).toEqual([
58
+ 'listener-id-1',
59
+ 'listener-id-2',
60
+ ]);
61
61
  });
62
62
 
63
- t.assert.strictEqual(filtered.length, 1);
64
- t.assert.strictEqual(filtered[0].userId, 'listener-id-1');
63
+ it('filter object supports boolean pin property', () => {
64
+ const filtered = applyParticipantsFilter(participants, {
65
+ roles: { $contains: 'listener' },
66
+ isPinned: true,
67
+ });
68
+
69
+ expect(filtered).toHaveLength(1);
70
+ expect(filtered[0].userId).toBe('listener-id-1');
71
+ });
65
72
  });
@@ -0,0 +1,54 @@
1
+ import clsx from 'clsx';
2
+ import { SfuModels } from '@stream-io/video-client';
3
+
4
+ export type ConnectionQualityIndicatorProps = {
5
+ quality: SfuModels.ConnectionQuality;
6
+ title?: string;
7
+ className?: string;
8
+ };
9
+
10
+ /** How many of the three bars are lit, per quality level. */
11
+ const ACTIVE_BARS: Partial<Record<SfuModels.ConnectionQuality, number>> = {
12
+ [SfuModels.ConnectionQuality.POOR]: 1,
13
+ [SfuModels.ConnectionQuality.GOOD]: 2,
14
+ [SfuModels.ConnectionQuality.EXCELLENT]: 3,
15
+ };
16
+
17
+ const BAR_COUNT = 3;
18
+
19
+ /**
20
+ * Three ascending bars showing a participant's connection quality.
21
+ */
22
+ export const ConnectionQualityIndicator = ({
23
+ quality,
24
+ title,
25
+ className,
26
+ }: ConnectionQualityIndicatorProps) => {
27
+ const activeBars = ACTIVE_BARS[quality];
28
+
29
+ if (!activeBars) return null;
30
+
31
+ const level = SfuModels.ConnectionQuality[quality].toLowerCase();
32
+
33
+ return (
34
+ <span
35
+ className={clsx(
36
+ 'str-video__connection-quality-indicator',
37
+ `str-video__connection-quality-indicator--${level}`,
38
+ className,
39
+ )}
40
+ title={title ?? level}
41
+ >
42
+ {Array.from({ length: BAR_COUNT }, (_, index) => (
43
+ <span
44
+ key={index}
45
+ className={clsx(
46
+ 'str-video__connection-quality-indicator__bar',
47
+ index < activeBars &&
48
+ 'str-video__connection-quality-indicator__bar--active',
49
+ )}
50
+ />
51
+ ))}
52
+ </span>
53
+ );
54
+ };
@@ -10,13 +10,14 @@ import {
10
10
  import {
11
11
  useCall,
12
12
  useCallStateHooks,
13
- useI18n,
14
13
  useIsAudioConnecting,
15
14
  useIsVideoConnecting,
16
15
  } from '@stream-io/video-react-bindings';
16
+ import { useI18n } from '../../../i18n';
17
17
  import clsx from 'clsx';
18
18
 
19
19
  import {
20
+ Button,
20
21
  Icon,
21
22
  IconButton,
22
23
  LoadingIndicator,
@@ -25,6 +26,7 @@ import {
25
26
  ToggleMenuButtonProps,
26
27
  } from '../../../components';
27
28
  import { ParticipantActionsContextMenu as DefaultParticipantActionsContextMenu } from './ParticipantActionsContextMenu';
29
+ import { ConnectionQualityIndicator } from './ConnectionQualityIndicator';
28
30
  import { Reaction } from '../../../components/Reaction';
29
31
  import { useParticipantViewContext } from './ParticipantViewContext';
30
32
 
@@ -56,7 +58,19 @@ export type DefaultParticipantViewUIProps = {
56
58
 
57
59
  const ToggleButton = forwardRef<HTMLButtonElement, ToggleMenuButtonProps>(
58
60
  function ToggleButtonRender(props, ref) {
59
- return <IconButton enabled={props.menuShown} icon="ellipsis" ref={ref} />;
61
+ const { t } = useI18n();
62
+
63
+ return (
64
+ <IconButton
65
+ className="str-video__participant-view__menu-button"
66
+ active={props.menuShown}
67
+ size="sm"
68
+ variant="secondary"
69
+ ref={ref}
70
+ title={t('participantView.moreOptions.title', 'More options')}
71
+ icon="ellipsis"
72
+ />
73
+ );
60
74
  },
61
75
  );
62
76
 
@@ -74,15 +88,19 @@ export const DefaultScreenShareOverlay = () => {
74
88
  <div className="str-video__screen-share-overlay">
75
89
  <Icon icon="screen-share-off" />
76
90
  <span className="str-video__screen-share-overlay__title">
77
- {t('You are presenting your screen')}
91
+ {t(
92
+ 'common.presentingYourScreen.text',
93
+ 'You are presenting your screen',
94
+ )}
78
95
  </span>
79
- <button
96
+ <Button
97
+ variant="destructive"
80
98
  onClick={stopScreenShare}
81
- type="button"
82
99
  className="str-video__screen-share-overlay__button"
83
100
  >
84
- <Icon icon="close" /> {t('Stop Screen Sharing')}
85
- </button>
101
+ <Icon icon="close" />{' '}
102
+ {t('participantView.stopScreenSharing.label', 'Stop Screen Sharing')}
103
+ </Button>
86
104
  </div>
87
105
  );
88
106
  };
@@ -107,10 +125,16 @@ export const DefaultAudioBlockedNotification = () => {
107
125
  <Icon icon="speaker" />
108
126
  <span className="str-video__audio-blocked-notification__text">
109
127
  <span className="str-video__audio-blocked-notification__title">
110
- {t('Audio is blocked by your system')}
128
+ {t(
129
+ 'participantView.audioBlocked.title',
130
+ 'Audio is blocked by your system',
131
+ )}
111
132
  </span>
112
133
  <span className="str-video__audio-blocked-notification__subtitle">
113
- {t('Click or tap to play audio')}
134
+ {t(
135
+ 'participantView.audioBlocked.description',
136
+ 'Click or tap to play audio',
137
+ )}
114
138
  </span>
115
139
  </span>
116
140
  </span>
@@ -182,10 +206,6 @@ export const ParticipantDetails = ({
182
206
  const call = useCall();
183
207
 
184
208
  const { t } = useI18n();
185
- const connectionQualityAsString =
186
- !!connectionQuality &&
187
- SfuModels.ConnectionQuality[connectionQuality].toLowerCase();
188
-
189
209
  const hasAudioTrack = hasAudio(participant);
190
210
  const hasVideoTrack = hasVideo(participant);
191
211
  const canUnpin = !!pin && pin.isLocalPin;
@@ -199,11 +219,16 @@ export const ParticipantDetails = ({
199
219
  <>
200
220
  <div className="str-video__participant-details">
201
221
  <div className="str-video__participant-details__name">
202
- {name || userId}
222
+ <span className="str-video__participant-details__name-text">
223
+ {name || userId}
224
+ </span>
203
225
  {indicatorsVisible && isAudioConnecting && (
204
226
  <LoadingIndicator
205
227
  className="str-video__participant-details__name--audio-connecting"
206
- tooltip={t('Audio is connecting...')}
228
+ tooltip={t(
229
+ 'participantView.audioConnecting.title',
230
+ 'Audio is connecting...',
231
+ )}
207
232
  />
208
233
  )}
209
234
  {indicatorsVisible && !hasAudioTrack && (
@@ -212,7 +237,10 @@ export const ParticipantDetails = ({
212
237
  {indicatorsVisible && isVideoConnecting && (
213
238
  <LoadingIndicator
214
239
  className="str-video__participant-details__name--video-connecting"
215
- tooltip={t('Video is connecting...')}
240
+ tooltip={t(
241
+ 'participantView.videoConnecting.title',
242
+ 'Video is connecting...',
243
+ )}
216
244
  />
217
245
  )}
218
246
  {indicatorsVisible && !hasVideoTrack && (
@@ -220,13 +248,20 @@ export const ParticipantDetails = ({
220
248
  )}
221
249
  {indicatorsVisible && isTrackPaused && (
222
250
  <span
223
- title={t('Video paused due to insufficient bandwidth')}
251
+ title={t(
252
+ 'participantView.videoPausedInsufficientBandwidth.title',
253
+ 'Video paused due to insufficient bandwidth',
254
+ )}
224
255
  className="str-video__participant-details__name--track-paused"
225
256
  />
226
257
  )}
227
258
  {indicatorsVisible && pin && (
228
259
  <span
229
- title={canUnpin ? t('Unpin') : t('Pinned')}
260
+ title={
261
+ canUnpin
262
+ ? t('participantView.unpin.label', 'Unpin')
263
+ : t('participantList.pinned.title', 'Pinned')
264
+ }
230
265
  onClick={canUnpin ? () => call?.unpin(sessionId) : undefined}
231
266
  className="str-video__participant-details__name--pinned"
232
267
  />
@@ -236,20 +271,18 @@ export const ParticipantDetails = ({
236
271
  </div>
237
272
  {indicatorsVisible && (
238
273
  <Notification
274
+ state="error"
239
275
  isVisible={
240
276
  isLocalParticipant &&
241
277
  connectionQuality === SfuModels.ConnectionQuality.POOR
242
278
  }
243
- message={t('Poor connection quality')}
279
+ message={t(
280
+ 'participantView.connectionQuality.poor.text',
281
+ 'Poor connection quality. Please check your internet connection.',
282
+ )}
244
283
  >
245
- {connectionQualityAsString && (
246
- <span
247
- className={clsx(
248
- 'str-video__participant-details__connection-quality',
249
- `str-video__participant-details__connection-quality--${connectionQualityAsString}`,
250
- )}
251
- title={connectionQualityAsString}
252
- />
284
+ {connectionQuality && (
285
+ <ConnectionQualityIndicator quality={connectionQuality} />
253
286
  )}
254
287
  </Notification>
255
288
  )}