@stream-io/video-react-sdk 2.0.0-beta.0 → 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 +24 -0
  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
@@ -3,6 +3,14 @@ import clsx from 'clsx';
3
3
  import { Placement } from '@floating-ui/react';
4
4
  import { useFloatingUIPreset } from '../../hooks';
5
5
 
6
+ export type NotificationState = 'success' | 'error' | 'loading';
7
+
8
+ const ICON_BY_STATE: Record<NotificationState, string> = {
9
+ success: 'checkmark',
10
+ error: 'exclamation-circle-fill',
11
+ loading: 'loading',
12
+ };
13
+
6
14
  export type NotificationProps = {
7
15
  message?: ReactNode;
8
16
  isVisible?: boolean;
@@ -10,7 +18,7 @@ export type NotificationProps = {
10
18
  resetIsVisible?: () => void;
11
19
  placement?: Placement;
12
20
  className?: string;
13
- iconClassName?: string | null;
21
+ state?: NotificationState;
14
22
  close?: () => void;
15
23
  };
16
24
 
@@ -23,7 +31,7 @@ export const Notification = (props: PropsWithChildren<NotificationProps>) => {
23
31
  resetIsVisible,
24
32
  placement = 'top',
25
33
  className,
26
- iconClassName = 'str-video__notification__icon',
34
+ state,
27
35
  close,
28
36
  } = props;
29
37
 
@@ -42,11 +50,19 @@ export const Notification = (props: PropsWithChildren<NotificationProps>) => {
42
50
  return () => clearTimeout(timeout);
43
51
  }, [isVisible, resetIsVisible, visibilityTimeout]);
44
52
 
53
+ const icon =
54
+ state && `str-video__icon str-video__icon--${ICON_BY_STATE[state]}`;
55
+
45
56
  return (
46
57
  <div className="str-video__notification-wrapper" ref={refs.setReference}>
47
58
  {isVisible && (
48
59
  <div
49
- className={clsx('str-video__notification', className)}
60
+ className={clsx(
61
+ 'str-video__notification',
62
+ state && `str-video__notification--${state}`,
63
+ close && 'str-video__notification--dismissible',
64
+ className,
65
+ )}
50
66
  ref={refs.setFloating}
51
67
  style={{
52
68
  position: strategy,
@@ -55,7 +71,7 @@ export const Notification = (props: PropsWithChildren<NotificationProps>) => {
55
71
  overflowY: 'auto',
56
72
  }}
57
73
  >
58
- {iconClassName && <i className={iconClassName} />}
74
+ {icon && <i className={icon} />}
59
75
  <span className="str-video__notification__message">{message}</span>
60
76
  {close ? (
61
77
  <i
@@ -77,6 +77,7 @@ export const PermissionNotification = (props: PermissionNotificationProps) => {
77
77
  if (isAwaitingApproval) {
78
78
  return (
79
79
  <Notification
80
+ state="loading"
80
81
  isVisible={isAwaitingApproval && !hasPermission}
81
82
  message={messageAwaitingApproval}
82
83
  >
@@ -87,6 +88,7 @@ export const PermissionNotification = (props: PermissionNotificationProps) => {
87
88
 
88
89
  return (
89
90
  <Notification
91
+ state={showNotification === 'granted' ? 'success' : 'error'}
90
92
  isVisible={!!showNotification}
91
93
  visibilityTimeout={visibilityTimeout}
92
94
  resetIsVisible={resetIsVisible}
@@ -1,8 +1,6 @@
1
1
  import { PropsWithChildren, useEffect, useState } from 'react';
2
- import {
3
- useI18n,
4
- useToggleCallRecording,
5
- } from '@stream-io/video-react-bindings';
2
+ import { useToggleCallRecording } from '@stream-io/video-react-bindings';
3
+ import { useI18n } from '../../i18n';
6
4
  import { Notification } from './Notification';
7
5
 
8
6
  export type RecordingInProgressNotificationProps = {
@@ -18,7 +16,9 @@ export const RecordingInProgressNotification = ({
18
16
 
19
17
  const [isVisible, setVisible] = useState(false);
20
18
 
21
- const message = text ?? t('Recording in progress...');
19
+ const message =
20
+ text ??
21
+ t('notification.recordingInProgress.text', 'Recording in progress...');
22
22
 
23
23
  useEffect(() => {
24
24
  if (isCallRecordingInProgress) {
@@ -31,7 +31,6 @@ export const RecordingInProgressNotification = ({
31
31
  return (
32
32
  <Notification
33
33
  message={message}
34
- iconClassName="str-video__icon str-video__icon--recording-on"
35
34
  isVisible={isVisible}
36
35
  placement="top-start"
37
36
  close={() => setVisible(false)}
@@ -1,7 +1,8 @@
1
1
  import { PropsWithChildren } from 'react';
2
2
  import { Placement } from '@floating-ui/react';
3
3
 
4
- import { useCallStateHooks, useI18n } from '@stream-io/video-react-bindings';
4
+ import { useCallStateHooks } from '@stream-io/video-react-bindings';
5
+ import { useI18n } from '../../i18n';
5
6
  import { Notification } from './Notification';
6
7
 
7
8
  export type SpeakingWhileMutedNotificationProps = {
@@ -21,7 +22,12 @@ export const SpeakingWhileMutedNotification = ({
21
22
  const { isSpeakingWhileMuted } = useMicrophoneState();
22
23
  const { t } = useI18n();
23
24
 
24
- const message = text ?? t('You are muted. Unmute to speak.');
25
+ const message =
26
+ text ??
27
+ t(
28
+ 'notification.speakingWhileMuted.text',
29
+ 'You are muted. Unmute to speak.',
30
+ );
25
31
  return (
26
32
  <Notification
27
33
  message={message}
@@ -1,9 +1,7 @@
1
1
  import {
2
- ButtonHTMLAttributes,
3
2
  ComponentProps,
4
3
  forwardRef,
5
4
  Fragment,
6
- PropsWithChildren,
7
5
  useEffect,
8
6
  useState,
9
7
  } from 'react';
@@ -12,14 +10,10 @@ import {
12
10
  PermissionRequestEvent,
13
11
  UserResponse,
14
12
  } from '@stream-io/video-client';
15
- import {
16
- TranslatorFunction,
17
- useCall,
18
- useCallStateHooks,
19
- useI18n,
20
- } from '@stream-io/video-react-bindings';
21
- import clsx from 'clsx';
13
+ import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
14
+ import { StreamTFunction, useI18n } from '../../i18n';
22
15
 
16
+ import { Button } from '../Button';
23
17
  import { useFloatingUIPreset } from '../../hooks';
24
18
 
25
19
  const byNameOrId = (a: UserResponse, b: UserResponse) => {
@@ -93,7 +87,10 @@ export const PermissionRequests = () => {
93
87
  {permissionRequests.length} pending permission requests
94
88
  </span>
95
89
  <Button
96
- type="button"
90
+ variant="secondary"
91
+ appearance="outline"
92
+ size="sm"
93
+ className="str-video__permission-request__button"
97
94
  onClick={() => {
98
95
  setExpanded((e) => !e);
99
96
  }}
@@ -143,25 +140,31 @@ export const PermissionRequestList = forwardRef<
143
140
  {messageForPermission(user.name || user.id, permission, t)}
144
141
  </div>
145
142
  <Button
146
- className="str-video__permission-request__button--allow"
147
- type="button"
143
+ variant="primary"
144
+ appearance="solid"
145
+ size="sm"
146
+ className="str-video__permission-request__button str-video__permission-request__button--allow"
148
147
  onClick={handleUpdatePermission(request, 'grant')}
149
148
  >
150
- {t('Allow')}
149
+ {t('common.allow.label', 'Allow')}
151
150
  </Button>
152
151
  <Button
153
- className="str-video__permission-request__button--reject"
154
- type="button"
152
+ variant="secondary"
153
+ appearance="outline"
154
+ size="sm"
155
+ className="str-video__permission-request__button str-video__permission-request__button--reject"
155
156
  onClick={handleUpdatePermission(request, 'revoke')}
156
157
  >
157
- {t('Revoke')}
158
+ {t('common.revoke.label', 'Revoke')}
158
159
  </Button>
159
160
  <Button
160
- className="str-video__permission-request__button--reject"
161
- type="button"
161
+ variant="secondary"
162
+ appearance="outline"
163
+ size="sm"
164
+ className="str-video__permission-request__button str-video__permission-request__button--reject"
162
165
  onClick={handleUpdatePermission(request, 'dismiss')}
163
166
  >
164
- {t('Dismiss')}
167
+ {t('common.dismiss.label', 'Dismiss')}
165
168
  </Button>
166
169
  </div>
167
170
  ))}
@@ -172,38 +175,42 @@ export const PermissionRequestList = forwardRef<
172
175
  );
173
176
  });
174
177
 
175
- const Button = (
176
- props: PropsWithChildren<ButtonHTMLAttributes<HTMLButtonElement>>,
177
- ) => {
178
- const { className, ...rest } = props;
179
- return (
180
- <button
181
- className={clsx('str-video__permission-request__button', className)}
182
- {...rest}
183
- />
184
- );
185
- };
186
-
187
178
  const messageForPermission = (
188
179
  userName: string,
189
180
  permission: string,
190
- t: TranslatorFunction,
181
+ t: StreamTFunction,
191
182
  ) => {
192
183
  switch (permission) {
193
184
  case OwnCapability.SEND_AUDIO:
194
- return t('{{ userName }} is requesting to speak', { userName });
185
+ return t(
186
+ 'permissions.requestingToSpeak.text',
187
+ '{{ userName }} is requesting to speak',
188
+ { userName },
189
+ );
195
190
  case OwnCapability.SEND_VIDEO:
196
- return t('{{ userName }} is requesting to share their camera', {
197
- userName,
198
- });
191
+ return t(
192
+ 'permissions.requestingCamera.text',
193
+ '{{ userName }} is requesting to share their camera',
194
+ {
195
+ userName,
196
+ },
197
+ );
199
198
  case OwnCapability.SCREENSHARE:
200
- return t('{{ userName }} is requesting to present their screen', {
201
- userName,
202
- });
199
+ return t(
200
+ 'permissions.requestingScreenShare.text',
201
+ '{{ userName }} is requesting to present their screen',
202
+ {
203
+ userName,
204
+ },
205
+ );
203
206
  default:
204
- return t('{{ userName }} is requesting permission: {{ permission }}', {
205
- userName,
206
- permission,
207
- });
207
+ return t(
208
+ 'permissions.requestingPermission.text',
209
+ '{{ userName }} is requesting permission: {{ permission }}',
210
+ {
211
+ userName,
212
+ permission,
213
+ },
214
+ );
208
215
  }
209
216
  };
@@ -3,22 +3,48 @@ import {
3
3
  useCall,
4
4
  useCallStateHooks,
5
5
  useConnectedUser,
6
- useI18n,
7
6
  } from '@stream-io/video-react-bindings';
7
+ import { StreamTFunction, useI18n } from '../../i18n';
8
8
  import { Avatar } from '../Avatar';
9
9
  import { RingingCallControls } from './RingingCallControls';
10
10
 
11
- const CALLING_STATE_TO_LABEL: Record<CallingState, string> = {
12
- [CallingState.JOINING]: 'Joining',
13
- [CallingState.RINGING]: 'Ringing',
14
- [CallingState.MIGRATING]: 'Migrating',
15
- [CallingState.RECONNECTING]: 'Re-connecting',
16
- [CallingState.RECONNECTING_FAILED]: 'Failed',
17
- [CallingState.OFFLINE]: 'No internet connection',
18
- [CallingState.IDLE]: '',
19
- [CallingState.UNKNOWN]: '',
20
- [CallingState.JOINED]: 'Joined',
21
- [CallingState.LEFT]: 'Left call',
11
+ /**
12
+ * The label rendered for the current calling state.
13
+ *
14
+ * A `switch` of literal `t()` calls rather than a `Record<CallingState, string>` fed into a `t()`
15
+ * lookup on a runtime value: the literal keys are statically extractable, which is what makes
16
+ * `Migrating`, `Failed`, `Joined` and `Left call` translatable - none had a catalog entry before.
17
+ * `IDLE` and `UNKNOWN` render nothing and get no key.
18
+ */
19
+ const getCallingStateLabel = (
20
+ callingState: CallingState,
21
+ t: StreamTFunction,
22
+ ): string | undefined => {
23
+ switch (callingState) {
24
+ case CallingState.JOINING:
25
+ return t('ringingCall.callingState.joining.text', 'Joining');
26
+ case CallingState.RINGING:
27
+ return t('ringingCall.callingState.ringing.text', 'Ringing');
28
+ case CallingState.MIGRATING:
29
+ return t('ringingCall.callingState.migrating.text', 'Migrating');
30
+ case CallingState.RECONNECTING:
31
+ return t('ringingCall.callingState.reconnecting.text', 'Re-connecting');
32
+ case CallingState.RECONNECTING_FAILED:
33
+ return t('ringingCall.callingState.reconnectingFailed.text', 'Failed');
34
+ case CallingState.OFFLINE:
35
+ return t(
36
+ 'ringingCall.callingState.offline.text',
37
+ 'No internet connection',
38
+ );
39
+ case CallingState.JOINED:
40
+ return t('ringingCall.callingState.joined.text', 'Joined');
41
+ case CallingState.LEFT:
42
+ return t('ringingCall.callingState.left.text', 'Left call');
43
+ case CallingState.IDLE:
44
+ case CallingState.UNKNOWN:
45
+ default:
46
+ return undefined;
47
+ }
22
48
  };
23
49
 
24
50
  export type RingingCallProps = {
@@ -63,7 +89,7 @@ export const RingingCall = (props: RingingCallProps) => {
63
89
  }
64
90
  }
65
91
 
66
- const callingStateLabel = CALLING_STATE_TO_LABEL[callingState];
92
+ const callingStateLabel = getCallingStateLabel(callingState, t);
67
93
 
68
94
  return (
69
95
  <div className="str-video__call-panel str-video__call-panel--ringing">
@@ -82,7 +108,7 @@ export const RingingCall = (props: RingingCallProps) => {
82
108
 
83
109
  {callingStateLabel && (
84
110
  <div className="str-video__call-panel__calling-state-label">
85
- {t(callingStateLabel)}
111
+ {callingStateLabel}
86
112
  </div>
87
113
  )}
88
114
 
@@ -13,11 +13,12 @@ export const RingingCallControls = () => {
13
13
  return (
14
14
  <div className="str-video__pending-call-controls">
15
15
  {call.isCreatedByMe ? (
16
- <CancelCallButton disabled={buttonsDisabled} />
16
+ <CancelCallButton size="sm" disabled={buttonsDisabled} />
17
17
  ) : (
18
18
  <>
19
19
  <AcceptCallButton disabled={buttonsDisabled} />
20
20
  <CancelCallButton
21
+ size="sm"
21
22
  onClick={() => {
22
23
  const reason = call.isCreatedByMe ? 'cancel' : 'decline';
23
24
  call.leave({ reject: true, reason }).catch((err) => {
@@ -42,16 +42,15 @@ export const SearchInput = ({
42
42
  'str-video__search-input__container--active': isActive,
43
43
  })}
44
44
  >
45
+ <span className="str-video__search-input__icon" />
45
46
  <input placeholder="Search" {...rest} ref={setInputElement} />
46
- {isActive ? (
47
+ {isActive && (
47
48
  <button
48
49
  className="str-video__search-input__clear-btn"
49
50
  onClick={exitSearch}
50
51
  >
51
52
  <span className="str-video__search-input__icon--active" />
52
53
  </button>
53
- ) : (
54
- <span className="str-video__search-input__icon" />
55
54
  )}
56
55
  </div>
57
56
  );
@@ -3,16 +3,18 @@ import clsx from 'clsx';
3
3
 
4
4
  export type StreamThemeProps = HTMLProps<HTMLElement> & {
5
5
  as?: ElementType;
6
+ theme?: string;
6
7
  };
7
8
 
8
9
  export const StreamTheme = ({
9
10
  as: Component = 'div',
10
11
  className,
11
12
  children,
13
+ theme = 'str-video__theme-dark',
12
14
  ...props
13
15
  }: PropsWithChildren<StreamThemeProps>) => {
14
16
  return (
15
- <Component {...props} className={clsx('str-video', className)}>
17
+ <Component {...props} className={clsx('str-video', theme, className)}>
16
18
  {children}
17
19
  </Component>
18
20
  );
@@ -1,7 +1,7 @@
1
- import { PropsWithChildren, useEffect, useRef } from 'react';
1
+ import { PropsWithChildren, useEffect } from 'react';
2
2
  import clsx from 'clsx';
3
3
  import { useFloatingUIPreset } from '../../hooks';
4
- import { FloatingArrow, Placement, arrow } from '@floating-ui/react';
4
+ import { Placement } from '@floating-ui/react';
5
5
 
6
6
  export type TooltipProps<T extends HTMLElement> = PropsWithChildren<{
7
7
  /** Reference element to which the tooltip should attach to */
@@ -23,11 +23,9 @@ export const Tooltip = <T extends HTMLElement>({
23
23
  tooltipPlacement = 'top',
24
24
  visible = false,
25
25
  }: TooltipProps<T>) => {
26
- const arrowRef = useRef<SVGSVGElement>(null);
27
- const { refs, x, y, strategy, context } = useFloatingUIPreset({
26
+ const { refs, x, y, strategy } = useFloatingUIPreset({
28
27
  placement: tooltipPlacement,
29
28
  strategy: 'absolute',
30
- middleware: [arrow({ element: arrowRef })],
31
29
  });
32
30
 
33
31
  useEffect(() => {
@@ -46,11 +44,6 @@ export const Tooltip = <T extends HTMLElement>({
46
44
  left: x ?? 0,
47
45
  }}
48
46
  >
49
- <FloatingArrow
50
- ref={arrowRef}
51
- context={context}
52
- fill="var(--str-video__tooltip--background-color)"
53
- />
54
47
  {children}
55
48
  </div>
56
49
  );
@@ -1,6 +1,8 @@
1
- import { ComponentType } from 'react';
1
+ import { ComponentType, useEffect, useState } from 'react';
2
2
  import clsx from 'clsx';
3
- import { useCallStateHooks, useI18n } from '@stream-io/video-react-bindings';
3
+ import { createSoundDetector } from '@stream-io/video-client';
4
+ import { useCallStateHooks } from '@stream-io/video-react-bindings';
5
+ import { useI18n } from '../../i18n';
4
6
  import { BaseVideo } from '../../core/components/Video';
5
7
  import { LoadingIndicator } from '../LoadingIndicator';
6
8
 
@@ -8,7 +10,7 @@ const DefaultDisabledVideoPreview = () => {
8
10
  const { t } = useI18n();
9
11
  return (
10
12
  <div className="str_video__video-preview__disabled-video-preview">
11
- {t('Video is disabled')}
13
+ {t('common.videoDisabled.text', 'Video is disabled')}
12
14
  </div>
13
15
  );
14
16
  };
@@ -17,11 +19,43 @@ const DefaultNoCameraPreview = () => {
17
19
  const { t } = useI18n();
18
20
  return (
19
21
  <div className="str_video__video-preview__no-camera-preview">
20
- {t('No camera found')}
22
+ {t('common.noCameraFound.text', 'No camera found')}
21
23
  </div>
22
24
  );
23
25
  };
24
26
 
27
+ /**
28
+ * Reports whether the local user is currently speaking, before they join the
29
+ * call. `MicrophoneManager` only runs its detector while the microphone is
30
+ * muted (for `speakingWhileMuted`), so this mirrors `AudioVolumeIndicator` and
31
+ * runs one on the live microphone stream instead.
32
+ */
33
+ const useLocalSpeaking = (enabled: boolean) => {
34
+ const { useMicrophoneState } = useCallStateHooks();
35
+ const { isEnabled, mediaStream } = useMicrophoneState();
36
+ const [isSpeaking, setIsSpeaking] = useState(false);
37
+
38
+ useEffect(() => {
39
+ if (!enabled || !isEnabled || !mediaStream) {
40
+ setIsSpeaking(false);
41
+ return;
42
+ }
43
+
44
+ const dispose = createSoundDetector(
45
+ mediaStream,
46
+ ({ isSoundDetected }) => setIsSpeaking(isSoundDetected),
47
+ { detectionFrequencyInMs: 80, destroyStreamOnStop: false },
48
+ );
49
+
50
+ return () => {
51
+ setIsSpeaking(false);
52
+ dispose().catch(console.error);
53
+ };
54
+ }, [enabled, isEnabled, mediaStream]);
55
+
56
+ return isSpeaking;
57
+ };
58
+
25
59
  export type VideoPreviewProps = {
26
60
  /**
27
61
  * Additional CSS class name to apply to the root element.
@@ -43,6 +77,11 @@ export type VideoPreviewProps = {
43
77
  * Component rendered above the BaseVideo until the video is ready (meaning until the play event is emitted).
44
78
  */
45
79
  StartingCameraPreview?: ComponentType;
80
+ /**
81
+ * Outlines the preview while the local user is speaking. Requires the
82
+ * microphone to be enabled. Defaults to false.
83
+ */
84
+ speakingIndicatorVisible?: boolean;
46
85
  };
47
86
 
48
87
  export const VideoPreview = ({
@@ -51,9 +90,11 @@ export const VideoPreview = ({
51
90
  DisabledVideoPreview = DefaultDisabledVideoPreview,
52
91
  NoCameraPreview = DefaultNoCameraPreview,
53
92
  StartingCameraPreview = LoadingIndicator,
93
+ speakingIndicatorVisible = false,
54
94
  }: VideoPreviewProps) => {
55
95
  const { useCameraState } = useCallStateHooks();
56
96
  const { devices, status, isMute, mediaStream } = useCameraState();
97
+ const isSpeaking = useLocalSpeaking(speakingIndicatorVisible);
57
98
 
58
99
  let contents;
59
100
  if (isMute && devices?.length === 0) {
@@ -79,7 +120,11 @@ export const VideoPreview = ({
79
120
  }
80
121
 
81
122
  return (
82
- <div className={clsx('str-video__video-preview-container', className)}>
123
+ <div
124
+ className={clsx('str-video__video-preview-container', className, {
125
+ 'str-video__video-preview-container--speaking': isSpeaking,
126
+ })}
127
+ >
83
128
  {contents}
84
129
  </div>
85
130
  );
@@ -1,11 +1,11 @@
1
1
  export * from './Avatar';
2
2
  export * from './BackgroundFilters';
3
+ export * from './Badge';
3
4
  export * from './Button';
4
5
  export * from './CallControls';
5
6
  export * from './CallParticipantsList';
6
7
  export * from './CallPreview';
7
8
  export * from './CallRecordingList';
8
- export * from './CallStats';
9
9
  export * from './DeviceSettings';
10
10
  export * from './DropdownSelect';
11
11
  export * from './Icon';