@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.
- package/CHANGELOG.md +24 -0
- package/dist/css/embedded.css +2592 -1498
- package/dist/css/embedded.css.map +1 -1
- package/dist/css/styles.css +2388 -1222
- package/dist/css/styles.css.map +1 -1
- package/dist/embedded.cjs.js +535 -476
- package/dist/embedded.cjs.js.map +1 -1
- package/dist/esm/index.js +10 -7
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/src/components/Avatar/Avatar.js +13 -5
- package/dist/esm/src/components/Avatar/Avatar.js.map +1 -1
- package/dist/esm/src/components/Badge/Badge.js +21 -0
- package/dist/esm/src/components/Badge/Badge.js.map +1 -0
- package/dist/esm/src/components/Button/Button.js +10 -0
- package/dist/esm/src/components/Button/Button.js.map +1 -0
- package/dist/esm/src/components/Button/CompositeButton.js +10 -17
- package/dist/esm/src/components/Button/CompositeButton.js.map +1 -1
- package/dist/esm/src/components/Button/IconButton.js +3 -9
- package/dist/esm/src/components/Button/IconButton.js.map +1 -1
- package/dist/esm/src/components/CallControls/AcceptCallButton.js +3 -2
- package/dist/esm/src/components/CallControls/AcceptCallButton.js.map +1 -1
- package/dist/esm/src/components/CallControls/CallControls.js +3 -0
- package/dist/esm/src/components/CallControls/CallControls.js.map +1 -1
- package/dist/esm/src/components/CallControls/CancelCallButton.js +11 -6
- package/dist/esm/src/components/CallControls/CancelCallButton.js.map +1 -1
- package/dist/esm/src/components/CallControls/ReactionsButton.js +7 -3
- package/dist/esm/src/components/CallControls/ReactionsButton.js.map +1 -1
- package/dist/esm/src/components/CallControls/RecordCallButton.js +17 -11
- package/dist/esm/src/components/CallControls/RecordCallButton.js.map +1 -1
- package/dist/esm/src/components/CallControls/ScreenShareButton.js +11 -4
- package/dist/esm/src/components/CallControls/ScreenShareButton.js.map +1 -1
- package/dist/esm/src/components/CallControls/ToggleAudioButton.js +28 -17
- package/dist/esm/src/components/CallControls/ToggleAudioButton.js.map +1 -1
- package/dist/esm/src/components/CallControls/ToggleAudioOutputButton.js +9 -4
- package/dist/esm/src/components/CallControls/ToggleAudioOutputButton.js.map +1 -1
- package/dist/esm/src/components/CallControls/ToggleVideoButton.js +32 -23
- package/dist/esm/src/components/CallControls/ToggleVideoButton.js.map +1 -1
- package/dist/esm/src/components/CallParticipantsList/BlockedUserListing.js +3 -3
- package/dist/esm/src/components/CallParticipantsList/BlockedUserListing.js.map +1 -1
- package/dist/esm/src/components/CallParticipantsList/CallParticipantListHeader.js +8 -3
- package/dist/esm/src/components/CallParticipantsList/CallParticipantListHeader.js.map +1 -1
- package/dist/esm/src/components/CallParticipantsList/CallParticipantListingItem.js +20 -7
- package/dist/esm/src/components/CallParticipantsList/CallParticipantListingItem.js.map +1 -1
- package/dist/esm/src/components/CallParticipantsList/CallParticipantsList.js +8 -5
- package/dist/esm/src/components/CallParticipantsList/CallParticipantsList.js.map +1 -1
- package/dist/esm/src/components/CallParticipantsList/EmptyParticipantSearchList.js +5 -2
- package/dist/esm/src/components/CallParticipantsList/EmptyParticipantSearchList.js.map +1 -1
- package/dist/esm/src/components/CallRecordingList/CallRecordingListHeader.js +7 -3
- package/dist/esm/src/components/CallRecordingList/CallRecordingListHeader.js.map +1 -1
- package/dist/esm/src/components/DeviceSettings/DeviceAudioPreviewItem.js +1 -1
- package/dist/esm/src/components/DeviceSettings/DeviceAudioPreviewItem.js.map +1 -1
- package/dist/esm/src/components/DeviceSettings/DeviceSelector.js +1 -1
- package/dist/esm/src/components/DeviceSettings/DeviceSelector.js.map +1 -1
- package/dist/esm/src/components/DeviceSettings/DeviceSelectorAudio.js +2 -2
- package/dist/esm/src/components/DeviceSettings/DeviceSelectorAudio.js.map +1 -1
- package/dist/esm/src/components/DeviceSettings/DeviceSettings.js +8 -5
- package/dist/esm/src/components/DeviceSettings/DeviceSettings.js.map +1 -1
- package/dist/esm/src/components/DeviceSettings/SpeakerTest.js +10 -4
- package/dist/esm/src/components/DeviceSettings/SpeakerTest.js.map +1 -1
- package/dist/esm/src/components/DropdownSelect/DropdownSelect.js +1 -1
- package/dist/esm/src/components/DropdownSelect/DropdownSelect.js.map +1 -1
- package/dist/esm/src/components/Menu/GenericMenu.js +2 -1
- package/dist/esm/src/components/Menu/GenericMenu.js.map +1 -1
- package/dist/esm/src/components/Menu/MenuToggle.js +3 -0
- package/dist/esm/src/components/Menu/MenuToggle.js.map +1 -1
- package/dist/esm/src/components/Notification/MicCaptureErrorNotification.js +6 -3
- package/dist/esm/src/components/Notification/MicCaptureErrorNotification.js.map +1 -1
- package/dist/esm/src/components/Notification/Notification.js +12 -3
- package/dist/esm/src/components/Notification/Notification.js.map +1 -1
- package/dist/esm/src/components/Notification/PermissionNotification.js +2 -2
- package/dist/esm/src/components/Notification/PermissionNotification.js.map +1 -1
- package/dist/esm/src/components/Notification/RecordingInProgressNotification.js +7 -3
- package/dist/esm/src/components/Notification/RecordingInProgressNotification.js.map +1 -1
- package/dist/esm/src/components/Notification/SpeakingWhileMutedNotification.js +7 -2
- package/dist/esm/src/components/Notification/SpeakingWhileMutedNotification.js.map +1 -1
- package/dist/esm/src/components/Permissions/PermissionRequests.js +13 -12
- package/dist/esm/src/components/Permissions/PermissionRequests.js.map +1 -1
- package/dist/esm/src/components/RingingCall/RingingCall.js +38 -14
- package/dist/esm/src/components/RingingCall/RingingCall.js.map +1 -1
- package/dist/esm/src/components/RingingCall/RingingCallControls.js +7 -3
- package/dist/esm/src/components/RingingCall/RingingCallControls.js.map +1 -1
- package/dist/esm/src/components/Search/SearchInput.js +1 -1
- package/dist/esm/src/components/Search/SearchInput.js.map +1 -1
- package/dist/esm/src/components/StreamTheme/StreamTheme.js +2 -2
- package/dist/esm/src/components/StreamTheme/StreamTheme.js.map +1 -1
- package/dist/esm/src/components/Tooltip/Tooltip.js +8 -8
- package/dist/esm/src/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/esm/src/components/VideoPreview/VideoPreview.js +36 -5
- package/dist/esm/src/components/VideoPreview/VideoPreview.js.map +1 -1
- package/dist/esm/src/core/components/CallLayout/LivestreamLayout.js +38 -12
- package/dist/esm/src/core/components/CallLayout/LivestreamLayout.js.map +1 -1
- package/dist/esm/src/core/components/CallLayout/PaginatedGridLayout.js +9 -5
- package/dist/esm/src/core/components/CallLayout/PaginatedGridLayout.js.map +1 -1
- package/dist/esm/src/core/components/CallLayout/PipLayout/Grid.js +9 -6
- package/dist/esm/src/core/components/CallLayout/PipLayout/Grid.js.map +1 -1
- package/dist/esm/src/core/components/CallLayout/PipLayout/Pip.js +9 -6
- package/dist/esm/src/core/components/CallLayout/PipLayout/Pip.js.map +1 -1
- package/dist/esm/src/core/components/CallLayout/SpeakerLayout.js +11 -6
- package/dist/esm/src/core/components/CallLayout/SpeakerLayout.js.map +1 -1
- package/dist/esm/src/core/components/ParticipantView/ConnectionQualityIndicator.js +25 -0
- package/dist/esm/src/core/components/ParticipantView/ConnectionQualityIndicator.js.map +1 -0
- package/dist/esm/src/core/components/ParticipantView/DefaultParticipantViewUI.js +17 -13
- package/dist/esm/src/core/components/ParticipantView/DefaultParticipantViewUI.js.map +1 -1
- package/dist/esm/src/core/components/ParticipantView/ParticipantActionsContextMenu.js +13 -8
- package/dist/esm/src/core/components/ParticipantView/ParticipantActionsContextMenu.js.map +1 -1
- package/dist/esm/src/core/components/StreamVideo/StreamVideo.js +24 -3
- package/dist/esm/src/core/components/StreamVideo/StreamVideo.js.map +1 -1
- package/dist/esm/src/core/components/Video/BaseVideoPlaceholder.js +3 -13
- package/dist/esm/src/core/components/Video/BaseVideoPlaceholder.js.map +1 -1
- package/dist/esm/src/core/components/Video/DefaultPictureInPicturePlaceholder.js +4 -2
- package/dist/esm/src/core/components/Video/DefaultPictureInPicturePlaceholder.js.map +1 -1
- package/dist/esm/src/core/components/Video/DefaultVideoPlaceholder.js +4 -2
- package/dist/esm/src/core/components/Video/DefaultVideoPlaceholder.js.map +1 -1
- package/dist/esm/src/embedded/EmbeddedClientProvider.js +7 -4
- package/dist/esm/src/embedded/EmbeddedClientProvider.js.map +1 -1
- package/dist/esm/src/embedded/call/CallControls.js +10 -6
- package/dist/esm/src/embedded/call/CallControls.js.map +1 -1
- package/dist/esm/src/embedded/call/CallHeader.js +10 -7
- package/dist/esm/src/embedded/call/CallHeader.js.map +1 -1
- package/dist/esm/src/embedded/call/CallLayout.js +8 -5
- package/dist/esm/src/embedded/call/CallLayout.js.map +1 -1
- package/dist/esm/src/embedded/call/CallStateRouter.js +7 -4
- package/dist/esm/src/embedded/call/CallStateRouter.js.map +1 -1
- package/dist/esm/src/embedded/hooks/useLayout.js +7 -4
- package/dist/esm/src/embedded/hooks/useLayout.js.map +1 -1
- package/dist/esm/src/embedded/livestream/host/HostLayout.js +12 -7
- package/dist/esm/src/embedded/livestream/host/HostLayout.js.map +1 -1
- package/dist/esm/src/embedded/livestream/host/HostStateRouter.js +12 -7
- package/dist/esm/src/embedded/livestream/host/HostStateRouter.js.map +1 -1
- package/dist/esm/src/embedded/livestream/viewer/ViewerLayout.js +9 -6
- package/dist/esm/src/embedded/livestream/viewer/ViewerLayout.js.map +1 -1
- package/dist/esm/src/embedded/livestream/viewer/ViewerLobby.js +12 -9
- package/dist/esm/src/embedded/livestream/viewer/ViewerLobby.js.map +1 -1
- package/dist/esm/src/embedded/livestream/viewer/ViewerStateRouter.js +7 -4
- package/dist/esm/src/embedded/livestream/viewer/ViewerStateRouter.js.map +1 -1
- package/dist/esm/src/embedded/shared/BlurToggleButton/BlurToggleButton.js +13 -9
- package/dist/esm/src/embedded/shared/BlurToggleButton/BlurToggleButton.js.map +1 -1
- package/dist/esm/src/embedded/shared/CallDuration/CallDuration.js +40 -0
- package/dist/esm/src/embedded/shared/CallDuration/CallDuration.js.map +1 -0
- package/dist/esm/src/embedded/shared/CallFeedback/CallEndedScreen.js +8 -6
- package/dist/esm/src/embedded/shared/CallFeedback/CallEndedScreen.js.map +1 -1
- package/dist/esm/src/embedded/shared/CallFeedback/RatingScreen.js +26 -2
- package/dist/esm/src/embedded/shared/CallFeedback/RatingScreen.js.map +1 -1
- package/dist/esm/src/embedded/shared/CallFeedback/StarRating.js +12 -6
- package/dist/esm/src/embedded/shared/CallFeedback/StarRating.js.map +1 -1
- package/dist/esm/src/embedded/shared/CallFeedback/ThankYouScreen.js +8 -6
- package/dist/esm/src/embedded/shared/CallFeedback/ThankYouScreen.js.map +1 -1
- package/dist/esm/src/embedded/shared/ConnectionNotification/ConnectionNotification.js +15 -14
- package/dist/esm/src/embedded/shared/ConnectionNotification/ConnectionNotification.js.map +1 -1
- package/dist/esm/src/embedded/shared/EmbeddedParticipantViewUI/EmbeddedParticipantViewUI.js +4 -0
- package/dist/esm/src/embedded/shared/EmbeddedParticipantViewUI/EmbeddedParticipantViewUI.js.map +1 -1
- package/dist/esm/src/embedded/shared/JoinError/JoinError.js +8 -6
- package/dist/esm/src/embedded/shared/JoinError/JoinError.js.map +1 -1
- package/dist/esm/src/embedded/shared/Lobby/DeviceControls.js +11 -7
- package/dist/esm/src/embedded/shared/Lobby/DeviceControls.js.map +1 -1
- package/dist/esm/src/embedded/shared/Lobby/DisabledDeviceButton.js +6 -4
- package/dist/esm/src/embedded/shared/Lobby/DisabledDeviceButton.js.map +1 -1
- package/dist/esm/src/embedded/shared/Lobby/Lobby.js +10 -9
- package/dist/esm/src/embedded/shared/Lobby/Lobby.js.map +1 -1
- package/dist/esm/src/embedded/shared/Lobby/ToggleCameraButton.js +6 -4
- package/dist/esm/src/embedded/shared/Lobby/ToggleCameraButton.js.map +1 -1
- package/dist/esm/src/embedded/shared/Lobby/ToggleMicButton.js +8 -6
- package/dist/esm/src/embedded/shared/Lobby/ToggleMicButton.js.map +1 -1
- package/dist/esm/src/embedded/shared/Lobby/VideoPreviewFallbacks.js +11 -9
- package/dist/esm/src/embedded/shared/Lobby/VideoPreviewFallbacks.js.map +1 -1
- package/dist/esm/src/embedded/shared/ViewersCount/ViewersCount.js +6 -4
- package/dist/esm/src/embedded/shared/ViewersCount/ViewersCount.js.map +1 -1
- package/dist/esm/src/hooks/useDeviceList.js +4 -2
- package/dist/esm/src/hooks/useDeviceList.js.map +1 -1
- package/dist/esm/src/i18n/Streami18n.js +58 -0
- package/dist/esm/src/i18n/Streami18n.js.map +1 -0
- package/dist/esm/src/i18n/TranslationContext.js +42 -0
- package/dist/esm/src/i18n/TranslationContext.js.map +1 -0
- package/dist/esm/src/i18n/runtimeDefaults.js +20 -0
- package/dist/esm/src/i18n/runtimeDefaults.js.map +1 -0
- package/dist/esm/src/i18n/useStreami18n.js +49 -0
- package/dist/esm/src/i18n/useStreami18n.js.map +1 -0
- package/dist/esm/src/wrappers/LivestreamPlayer/LivestreamPlayer.js +4 -0
- package/dist/esm/src/wrappers/LivestreamPlayer/LivestreamPlayer.js.map +1 -1
- package/dist/index.cjs.js +559 -623
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/src/components/Avatar/Avatar.d.ts +9 -4
- package/dist/src/components/Badge/Badge.d.ts +23 -0
- package/dist/src/components/Badge/index.d.ts +1 -0
- package/dist/src/components/Button/Button.d.ts +16 -0
- package/dist/src/components/Button/CompositeButton.d.ts +6 -3
- package/dist/src/components/Button/IconButton.d.ts +7 -7
- package/dist/src/components/Button/index.d.ts +2 -2
- package/dist/src/components/CallControls/CancelCallButton.d.ts +3 -1
- package/dist/src/components/CallControls/ToggleAudioButton.d.ts +3 -3
- package/dist/src/components/CallControls/ToggleAudioOutputButton.d.ts +2 -2
- package/dist/src/components/CallControls/ToggleVideoButton.d.ts +3 -3
- package/dist/src/components/CallControls/index.d.ts +0 -1
- package/dist/src/components/Menu/GenericMenu.d.ts +1 -0
- package/dist/src/components/Notification/Notification.d.ts +2 -1
- package/dist/src/components/StreamTheme/StreamTheme.d.ts +2 -1
- package/dist/src/components/VideoPreview/VideoPreview.d.ts +6 -1
- package/dist/src/components/index.d.ts +1 -1
- package/dist/src/core/components/ParticipantView/ConnectionQualityIndicator.d.ts +10 -0
- package/dist/src/core/components/ParticipantView/index.d.ts +1 -0
- package/dist/src/core/components/StreamVideo/StreamVideo.d.ts +18 -2
- package/dist/src/embedded/shared/CallDuration/CallDuration.d.ts +9 -0
- package/dist/src/embedded/shared/index.d.ts +1 -0
- package/dist/src/i18n/Streami18n.d.ts +56 -0
- package/dist/src/i18n/TranslationContext.d.ts +30 -0
- package/dist/src/i18n/index.d.ts +16 -0
- package/dist/src/i18n/keys.d.ts +164 -0
- package/dist/src/i18n/runtimeDefaults.d.ts +17 -0
- package/dist/src/i18n/types.d.ts +45 -0
- package/dist/src/i18n/useStreami18n.d.ts +19 -0
- package/index.ts +1 -1
- package/package.json +18 -13
- package/src/components/Avatar/Avatar.tsx +53 -19
- package/src/components/Badge/Badge.tsx +48 -0
- package/src/components/Badge/index.ts +1 -0
- package/src/components/Button/Button.tsx +49 -0
- package/src/components/Button/CompositeButton.tsx +82 -73
- package/src/components/Button/IconButton.tsx +19 -29
- package/src/components/Button/index.ts +2 -2
- package/src/components/CallControls/AcceptCallButton.tsx +3 -1
- package/src/components/CallControls/CancelCallButton.tsx +32 -24
- package/src/components/CallControls/ReactionsButton.tsx +7 -3
- package/src/components/CallControls/RecordCallButton.tsx +50 -23
- package/src/components/CallControls/ScreenShareButton.tsx +27 -6
- package/src/components/CallControls/ToggleAudioButton.tsx +62 -61
- package/src/components/CallControls/ToggleAudioOutputButton.tsx +7 -4
- package/src/components/CallControls/ToggleVideoButton.tsx +66 -66
- package/src/components/CallControls/index.ts +0 -1
- package/src/components/CallParticipantsList/BlockedUserListing.tsx +9 -2
- package/src/components/CallParticipantsList/CallParticipantListHeader.tsx +10 -3
- package/src/components/CallParticipantsList/CallParticipantListingItem.tsx +33 -8
- package/src/components/CallParticipantsList/CallParticipantsList.tsx +21 -5
- package/src/components/CallParticipantsList/EmptyParticipantSearchList.tsx +2 -2
- package/src/components/CallRecordingList/CallRecordingListHeader.tsx +11 -3
- package/src/components/DeviceSettings/DeviceAudioPreviewItem.tsx +3 -1
- package/src/components/DeviceSettings/DeviceSelector.tsx +1 -1
- package/src/components/DeviceSettings/DeviceSelectorAudio.tsx +2 -7
- package/src/components/DeviceSettings/DeviceSettings.tsx +14 -5
- package/src/components/DeviceSettings/SpeakerTest.tsx +7 -2
- package/src/components/DropdownSelect/DropdownSelect.tsx +3 -1
- package/src/components/Menu/GenericMenu.tsx +4 -0
- package/src/components/Notification/MicCaptureErrorNotification.tsx +7 -2
- package/src/components/Notification/Notification.tsx +20 -4
- package/src/components/Notification/PermissionNotification.tsx +2 -0
- package/src/components/Notification/RecordingInProgressNotification.tsx +5 -6
- package/src/components/Notification/SpeakingWhileMutedNotification.tsx +8 -2
- package/src/components/Permissions/PermissionRequests.tsx +50 -43
- package/src/components/RingingCall/RingingCall.tsx +40 -14
- package/src/components/RingingCall/RingingCallControls.tsx +2 -1
- package/src/components/Search/SearchInput.tsx +2 -3
- package/src/components/StreamTheme/StreamTheme.tsx +3 -1
- package/src/components/Tooltip/Tooltip.tsx +3 -10
- package/src/components/VideoPreview/VideoPreview.tsx +50 -5
- package/src/components/index.ts +1 -1
- package/src/core/components/CallLayout/LivestreamLayout.tsx +48 -18
- package/src/core/components/CallLayout/PaginatedGridLayout.tsx +14 -0
- package/src/core/components/CallLayout/PipLayout/Grid.tsx +10 -2
- package/src/core/components/CallLayout/PipLayout/Pip.tsx +6 -2
- package/src/core/components/CallLayout/SpeakerLayout.tsx +27 -0
- package/src/core/components/CallLayout/partcipantFilter.test.ts +38 -31
- package/src/core/components/ParticipantView/ConnectionQualityIndicator.tsx +54 -0
- package/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx +60 -27
- package/src/core/components/ParticipantView/ParticipantActionsContextMenu.tsx +63 -22
- package/src/core/components/ParticipantView/index.ts +1 -0
- package/src/core/components/StreamVideo/StreamVideo.tsx +39 -4
- package/src/core/components/Video/BaseVideoPlaceholder.tsx +13 -30
- package/src/core/components/Video/DefaultPictureInPicturePlaceholder.tsx +5 -2
- package/src/core/components/Video/DefaultVideoPlaceholder.tsx +2 -2
- package/src/embedded/call/CallControls.tsx +9 -18
- package/src/embedded/call/CallHeader.tsx +3 -12
- package/src/embedded/call/CallLayout.tsx +1 -1
- package/src/embedded/livestream/host/HostLayout.tsx +26 -20
- package/src/embedded/livestream/host/HostStateRouter.tsx +12 -8
- package/src/embedded/livestream/viewer/ViewerLayout.tsx +8 -11
- package/src/embedded/livestream/viewer/ViewerLobby.tsx +31 -15
- package/src/embedded/shared/BlurToggleButton/BlurToggleButton.tsx +18 -12
- package/src/embedded/shared/CallDuration/CallDuration.tsx +32 -0
- package/src/embedded/shared/CallFeedback/CallEndedScreen.tsx +27 -13
- package/src/embedded/shared/CallFeedback/RatingScreen.tsx +20 -12
- package/src/embedded/shared/CallFeedback/StarRating.tsx +10 -3
- package/src/embedded/shared/CallFeedback/ThankYouScreen.tsx +6 -3
- package/src/embedded/shared/ConnectionNotification/ConnectionNotification.tsx +21 -14
- package/src/embedded/shared/JoinError/JoinError.tsx +7 -6
- package/src/embedded/shared/Lobby/DeviceControls.tsx +25 -3
- package/src/embedded/shared/Lobby/Lobby.tsx +19 -22
- package/src/embedded/shared/Lobby/ToggleMicButton.tsx +10 -3
- package/src/embedded/shared/Lobby/VideoPreviewFallbacks.tsx +4 -2
- package/src/embedded/shared/index.ts +1 -0
- package/src/hooks/useDeviceList.tsx +2 -2
- package/src/i18n/Streami18n.ts +67 -0
- package/src/i18n/TranslationContext.tsx +55 -0
- package/src/i18n/index.ts +22 -0
- package/src/i18n/keys.ts +169 -0
- package/src/i18n/runtimeDefaults.ts +17 -0
- package/src/i18n/types.ts +78 -0
- package/src/i18n/useStreami18n.ts +66 -0
- package/src/utilities/filter.test.ts +132 -124
- package/src/utilities/normalizeString.test.ts +50 -48
- package/dist/embedded-CallStatsLatencyChart-CpL1M_s0.cjs.js +0 -59
- package/dist/embedded-CallStatsLatencyChart-CpL1M_s0.cjs.js.map +0 -1
- package/dist/esm/src/components/Button/TextButton.js +0 -8
- package/dist/esm/src/components/Button/TextButton.js.map +0 -1
- package/dist/esm/src/components/CallControls/CallStatsButton.js +0 -18
- package/dist/esm/src/components/CallControls/CallStatsButton.js.map +0 -1
- package/dist/esm/src/components/CallStats/CallStats.js +0 -180
- package/dist/esm/src/components/CallStats/CallStats.js.map +0 -1
- package/dist/esm/src/components/CallStats/CallStatsLatencyChart.js +0 -57
- package/dist/esm/src/components/CallStats/CallStatsLatencyChart.js.map +0 -1
- package/dist/esm/src/translations/en.json.js +0 -177
- package/dist/esm/src/translations/en.json.js.map +0 -1
- package/dist/esm/src/translations/index.js +0 -6
- package/dist/esm/src/translations/index.js.map +0 -1
- package/dist/latency-chart-CpL1M_s0.cjs.js +0 -59
- package/dist/latency-chart-CpL1M_s0.cjs.js.map +0 -1
- package/dist/src/components/Button/TextButton.d.ts +0 -2
- package/dist/src/components/CallControls/CallStatsButton.d.ts +0 -4
- package/dist/src/components/CallStats/CallStats.d.ts +0 -22
- package/dist/src/components/CallStats/CallStatsLatencyChart.d.ts +0 -7
- package/dist/src/components/CallStats/index.d.ts +0 -1
- package/dist/src/translations/index.d.ts +0 -146
- package/src/components/Button/TextButton.tsx +0 -12
- package/src/components/CallControls/CallStatsButton.tsx +0 -37
- package/src/components/CallStats/CallStats.tsx +0 -439
- package/src/components/CallStats/CallStatsLatencyChart.tsx +0 -76
- package/src/components/CallStats/index.ts +0 -1
- package/src/translations/en.json +0 -154
- package/src/translations/index.ts +0 -3
package/dist/index.cjs.js
CHANGED
|
@@ -4,7 +4,9 @@ var videoClient = require('@stream-io/video-client');
|
|
|
4
4
|
var videoReactBindings = require('@stream-io/video-react-bindings');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
var react = require('react');
|
|
7
|
-
var
|
|
7
|
+
var i18n = require('@stream-io/i18n');
|
|
8
|
+
var react$1 = require('@stream-io/i18n/react');
|
|
9
|
+
var react$2 = require('@floating-ui/react');
|
|
8
10
|
var clsx = require('clsx');
|
|
9
11
|
|
|
10
12
|
const Audio = react.memo(function AudioRender({ participant, trackType = 'audioTrack', ...rest }) {
|
|
@@ -39,18 +41,169 @@ const ParticipantsAudio = (props) => {
|
|
|
39
41
|
};
|
|
40
42
|
ParticipantsAudio.displayName = 'ParticipantsAudio';
|
|
41
43
|
|
|
44
|
+
/**
|
|
45
|
+
* The SDK's bundled translation data: the keys that cannot carry an inline `defaultValue` at their
|
|
46
|
+
* call site. `Streami18n` layers it under *every* language, so a partial dictionary never knocks
|
|
47
|
+
* these out.
|
|
48
|
+
*
|
|
49
|
+
* Empty, and that is the intended steady state. The four lookups this SDK resolved from a runtime
|
|
50
|
+
* value — the only candidates for an entry here — are written as `switch` statements over literal
|
|
51
|
+
* `t()` calls instead, so every branch carries its own English copy inline and the codegen reads it
|
|
52
|
+
* straight off the call site. Nothing is left without a default. `timestamp.*` / `duration.*`
|
|
53
|
+
* formatter expressions would also live here; this SDK has none yet.
|
|
54
|
+
*
|
|
55
|
+
* Adding an entry later needs no wiring. `Streami18n` already spreads this into the core options and
|
|
56
|
+
* `scripts/generate-i18n-keys.mts` already reads this path, so a new key reaches `keys.ts` on the
|
|
57
|
+
* next `build-translations` run — where a key nothing references, or one that shadows an inline
|
|
58
|
+
* default, fails a codegen guard.
|
|
59
|
+
*/
|
|
60
|
+
const runtimeDefaults = {};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Wrapper around [i18next](https://www.i18next.com/) for this SDK's translations. Pass an instance
|
|
64
|
+
* to `<StreamVideo i18nInstance={…}>` to control the language and the copy.
|
|
65
|
+
*
|
|
66
|
+
* The implementation lives in `@stream-io/i18n`, shared with the React Native SDK and with Chat.
|
|
67
|
+
* What this subclass adds is what is this package's own: its bundled translation data, and the two
|
|
68
|
+
* type parameters — core cannot supply either, because the key catalog is generated from *this*
|
|
69
|
+
* package's `t()` call sites.
|
|
70
|
+
*
|
|
71
|
+
* ## Overriding some of the English copy
|
|
72
|
+
*
|
|
73
|
+
* ```ts
|
|
74
|
+
* const i18n = new Streami18n({
|
|
75
|
+
* translationsForLanguage: {
|
|
76
|
+
* 'common.participants.label': 'People',
|
|
77
|
+
* },
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* ## Adding a language
|
|
82
|
+
*
|
|
83
|
+
* ```ts
|
|
84
|
+
* import 'dayjs/locale/nl';
|
|
85
|
+
*
|
|
86
|
+
* const i18n = new Streami18n({ language: 'nl' });
|
|
87
|
+
* i18n.registerTranslation('nl', {
|
|
88
|
+
* 'callControls.cancelCallButton.leaveCall.title': 'Verlaten',
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* No dayjs locale file defines `calendar` — that field belongs to the calendar plugin — so a
|
|
93
|
+
* language whose relative dates must read natively needs the locale import *and* a `calendar`
|
|
94
|
+
* config passed as the third argument.
|
|
95
|
+
*
|
|
96
|
+
* Type your dictionary as `TranslationDictionary` to turn a typo or a key removed in a later major
|
|
97
|
+
* into a compile error. A **partial dictionary is safe**: any key you leave out renders the English
|
|
98
|
+
* copy that ships inline at each call site, never a raw dotted path — so there is no need to
|
|
99
|
+
* translate everything before shipping a language.
|
|
100
|
+
*
|
|
101
|
+
* Reactivity goes through `i18n.state`, a `StateStore`. `setLanguage()` returns nothing — the new
|
|
102
|
+
* `t` is published to that store, which the provider subscribes to.
|
|
103
|
+
*/
|
|
104
|
+
class Streami18n extends i18n.Streami18n {
|
|
105
|
+
constructor(options = {}) {
|
|
106
|
+
super({
|
|
107
|
+
...options,
|
|
108
|
+
// Merged, not replaced. Spreading `options` over a literal would let an integrator supplying
|
|
109
|
+
// one entry silently drop the SDK's own bundled data, which then renders as raw keys.
|
|
110
|
+
runtimeDefaults: { ...runtimeDefaults, ...options.runtimeDefaults },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The `t` in force before i18next has initialized, and the context's default.
|
|
117
|
+
*
|
|
118
|
+
* Core's factory, instantiated against this SDK's catalog so it is typed exactly like the real `t`.
|
|
119
|
+
* It honours the inline `defaultValue` each prose call site passes, which is what stops raw dotted
|
|
120
|
+
* keys flashing on the first frame.
|
|
121
|
+
*/
|
|
122
|
+
const defaultTranslatorFunction = i18n.createDefaultTranslatorFunction();
|
|
123
|
+
/**
|
|
124
|
+
* Built from the shared factory in `@stream-io/i18n/react`.
|
|
125
|
+
*
|
|
126
|
+
* A **default value** is supplied rather than making the hook throw, and that is deliberate: it
|
|
127
|
+
* matches what `useI18n` did before this module existed, and it is what lets the `embedded/`
|
|
128
|
+
* components — which are used standalone, outside any provider — render correct English instead of
|
|
129
|
+
* crashing. Chat's React Native SDK throws instead; hence core exposes this as a factory.
|
|
130
|
+
*/
|
|
131
|
+
const { TranslationContext, TranslationProvider, useTranslationContext } = react$1.createTranslationContext({
|
|
132
|
+
defaultValue: {
|
|
133
|
+
t: defaultTranslatorFunction,
|
|
134
|
+
tDateTimeParser: i18n.defaultDateTimeParser,
|
|
135
|
+
},
|
|
136
|
+
displayName: 'StreamVideoTranslationContext',
|
|
137
|
+
});
|
|
138
|
+
/**
|
|
139
|
+
* Reads `t` and `tDateTimeParser` from the closest provider.
|
|
140
|
+
*
|
|
141
|
+
* Works outside a provider too — the default translator renders each call site's inline English.
|
|
142
|
+
*
|
|
143
|
+
* The name is `useI18n` rather than core's `useTranslationContext` because ~500 call sites in this
|
|
144
|
+
* SDK already import it; renaming them is churn with no payoff.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* const { t } = useI18n();
|
|
148
|
+
* const label = t('callControls.cancelCallButton.leaveCall.title', 'Leave call');
|
|
149
|
+
*/
|
|
150
|
+
const useI18n = useTranslationContext;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Resolves the translation context value: creates or adopts a {@link Streami18n} instance,
|
|
154
|
+
* registers the supplied dictionaries, initializes it and keeps `t` fresh across language changes.
|
|
155
|
+
*
|
|
156
|
+
* `init()` and the store subscription belong to `useStreami18nState` in `@stream-io/i18n/react`,
|
|
157
|
+
* shared with the React Native SDK.
|
|
158
|
+
*/
|
|
159
|
+
const useStreami18n = ({ i18nInstance, language, translations, }) => {
|
|
160
|
+
// Lazy `useState`, not `useMemo`: `new Streami18n()` is a real allocation with identity that must
|
|
161
|
+
// survive a re-render, and this repo lints `react-hooks/purity` as an error — `useMemo` is a
|
|
162
|
+
// cache React is free to drop, so constructing there is a purity violation. A later change to
|
|
163
|
+
// `i18nInstance` is ignored on purpose; swapping the instance mid-tree is not a supported move.
|
|
164
|
+
const [i18n] = react.useState(() => {
|
|
165
|
+
const instance = i18nInstance ?? new Streami18n({ language });
|
|
166
|
+
// Registered here rather than in an effect. `useStreami18nState` calls `init()` from its own
|
|
167
|
+
// effect, which runs *before* any effect declared below it in this hook — so a dictionary
|
|
168
|
+
// registered in an effect would arrive after i18next was already initialized, and the first
|
|
169
|
+
// `init()` would warn that the language has no dictionary.
|
|
170
|
+
if (translations) {
|
|
171
|
+
for (const [code, dictionary] of Object.entries(translations)) {
|
|
172
|
+
instance.registerTranslation(code, dictionary);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return instance;
|
|
176
|
+
});
|
|
177
|
+
// No `onInitError` handler: core already logs a warning and leaves the instance usable, with `t`
|
|
178
|
+
// still rendering each call site's inline English. Pass one only to surface init failures
|
|
179
|
+
// somewhere other than the console.
|
|
180
|
+
const translators = react$1.useStreami18nState(i18n);
|
|
181
|
+
react.useEffect(() => {
|
|
182
|
+
// Guarded on the current value: `setLanguage` re-runs the formatter factories and a full
|
|
183
|
+
// i18next `changeLanguage`, and the first render already constructed the instance with
|
|
184
|
+
// `language`. Undefined means "leave whatever the instance was configured with".
|
|
185
|
+
if (!language || i18n.currentLanguage === language)
|
|
186
|
+
return;
|
|
187
|
+
i18n.setLanguage(language);
|
|
188
|
+
}, [i18n, language]);
|
|
189
|
+
// Returned as-is: `useStreami18nState` already caches this object and only produces a new one
|
|
190
|
+
// when `t` or `tDateTimeParser` actually changes, so wrapping it in a `useMemo` would add a
|
|
191
|
+
// second cache over a stable value.
|
|
192
|
+
return translators;
|
|
193
|
+
};
|
|
194
|
+
|
|
42
195
|
const ParticipantViewContext = react.createContext(undefined);
|
|
43
196
|
const useParticipantViewContext = () => react.useContext(ParticipantViewContext);
|
|
44
197
|
|
|
45
198
|
const useFloatingUIPreset = ({ middleware = [], placement, strategy, offset: offsetInPx = 10, }) => {
|
|
46
|
-
const { refs, x, y, update, elements: { domReference, floating }, context, } = react$
|
|
199
|
+
const { refs, x, y, update, elements: { domReference, floating }, context, } = react$2.useFloating({
|
|
47
200
|
placement,
|
|
48
201
|
strategy,
|
|
49
202
|
middleware: [
|
|
50
|
-
react$
|
|
51
|
-
react$
|
|
52
|
-
react$
|
|
53
|
-
react$
|
|
203
|
+
react$2.offset(offsetInPx),
|
|
204
|
+
react$2.shift(),
|
|
205
|
+
react$2.flip(),
|
|
206
|
+
react$2.size({
|
|
54
207
|
padding: 10,
|
|
55
208
|
apply: ({ availableHeight, elements }) => {
|
|
56
209
|
Object.assign(elements.floating.style, {
|
|
@@ -65,7 +218,7 @@ const useFloatingUIPreset = ({ middleware = [], placement, strategy, offset: off
|
|
|
65
218
|
react.useEffect(() => {
|
|
66
219
|
if (!domReference || !floating)
|
|
67
220
|
return;
|
|
68
|
-
const cleanup = react$
|
|
221
|
+
const cleanup = react$2.autoUpdate(domReference, floating, update);
|
|
69
222
|
return () => cleanup();
|
|
70
223
|
}, [domReference, floating, update]);
|
|
71
224
|
return { refs, x, y, domReference, floating, strategy, context };
|
|
@@ -189,7 +342,7 @@ const useRequestPermission = (permission) => {
|
|
|
189
342
|
* 2. Maps the device list to a format more suitable for rendering.
|
|
190
343
|
*/
|
|
191
344
|
function useDeviceList(devices, selectedDeviceId) {
|
|
192
|
-
const { t } =
|
|
345
|
+
const { t } = useI18n();
|
|
193
346
|
return react.useMemo(() => {
|
|
194
347
|
let selectedDeviceInfo = null;
|
|
195
348
|
let selectedIndex = null;
|
|
@@ -205,7 +358,7 @@ function useDeviceList(devices, selectedDeviceId) {
|
|
|
205
358
|
if (selectedDeviceInfo === null || selectedIndex === null) {
|
|
206
359
|
const defaultDevice = {
|
|
207
360
|
deviceId: 'default',
|
|
208
|
-
label: t('Default'),
|
|
361
|
+
label: t('common.default.label', 'Default'),
|
|
209
362
|
isSelected: true,
|
|
210
363
|
};
|
|
211
364
|
selectedDeviceInfo = defaultDevice;
|
|
@@ -607,7 +760,7 @@ const useMenuContext = () => {
|
|
|
607
760
|
};
|
|
608
761
|
const MenuPortal = ({ children, refs, }) => {
|
|
609
762
|
const [portalRoot, setPortalRoot] = react.useState(null);
|
|
610
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { ref: setPortalRoot, className: "str-video__portal" }), jsxRuntime.jsx(react$
|
|
763
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { ref: setPortalRoot, className: "str-video__portal" }), jsxRuntime.jsx(react$2.FloatingOverlay, { children: jsxRuntime.jsx(react$2.FloatingPortal, { root: portalRoot, children: jsxRuntime.jsx("div", { className: "str-video__portal-content", ref: refs.setFloating, children: children }) }) })] }));
|
|
611
764
|
};
|
|
612
765
|
const MenuToggle = ({ ToggleButton, placement = 'top-start', strategy = 'absolute', offset, visualType = exports.MenuVisualType.MENU, children, onToggle, }) => {
|
|
613
766
|
const [menuShown, setMenuShown] = react.useState(false);
|
|
@@ -669,6 +822,7 @@ const GenericMenu = ({ children, onItemClick, }) => {
|
|
|
669
822
|
const GenericMenuButtonItem = ({ children, ...rest }) => {
|
|
670
823
|
return (jsxRuntime.jsx("li", { className: "str-video__generic-menu--item", children: jsxRuntime.jsx("button", { ...rest, children: children }) }));
|
|
671
824
|
};
|
|
825
|
+
const GenericMenuSeparator = () => (jsxRuntime.jsx("li", { className: "str-video__generic-menu--separator", role: "separator" }));
|
|
672
826
|
|
|
673
827
|
const Icon = ({ className, icon }) => (jsxRuntime.jsx("span", { className: clsx('str-video__icon', icon && `str-video__icon--${icon}`, className) }));
|
|
674
828
|
|
|
@@ -697,7 +851,7 @@ const ParticipantActionsContextMenu = () => {
|
|
|
697
851
|
const [fullscreenModeOn, setFullscreenModeOn] = react.useState(!!document.fullscreenElement);
|
|
698
852
|
const call = videoReactBindings.useCall();
|
|
699
853
|
const isPiP = usePictureInPictureState(videoElement ?? undefined);
|
|
700
|
-
const { t } =
|
|
854
|
+
const { t } = useI18n();
|
|
701
855
|
const { pin, sessionId, userId } = participant;
|
|
702
856
|
const hasAudioTrack = videoClient.hasAudio(participant);
|
|
703
857
|
const hasVideoTrack = videoClient.hasVideo(participant);
|
|
@@ -769,12 +923,14 @@ const ParticipantActionsContextMenu = () => {
|
|
|
769
923
|
return document.exitPictureInPicture().catch(console.error);
|
|
770
924
|
};
|
|
771
925
|
const { close } = useMenuContext() || {};
|
|
772
|
-
return (jsxRuntime.jsxs(GenericMenu, { onItemClick: close, children: [jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: toggleParticipantPin, disabled: pin && !pin.isLocalPin, children: [jsxRuntime.jsx(Icon, { icon: "pin" }), pin
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
926
|
+
return (jsxRuntime.jsxs(GenericMenu, { onItemClick: close, children: [jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: toggleParticipantPin, disabled: pin && !pin.isLocalPin, children: [jsxRuntime.jsx(Icon, { icon: "pin" }), pin
|
|
927
|
+
? t('participantView.unpin.label', 'Unpin')
|
|
928
|
+
: t('participantView.actionsMenu.pin.label', 'Pin')] }), jsxRuntime.jsxs(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.PIN_FOR_EVERYONE], children: [jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: pinForEveryone, disabled: pin && !pin.isLocalPin, children: [jsxRuntime.jsx(Icon, { icon: "pin" }), t('participantView.actionsMenu.pinForEveryone.label', 'Pin for everyone')] }), jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: unpinForEveryone, disabled: !pin || pin.isLocalPin, children: [jsxRuntime.jsx(Icon, { icon: "pin" }), t('participantView.actionsMenu.unpinForEveryone.label', 'Unpin for everyone')] })] }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.BLOCK_USERS], children: jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: blockUser, children: [jsxRuntime.jsx(Icon, { icon: "not-allowed" }), t('participantView.actionsMenu.block.label', 'Block')] }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.KICK_USER], children: jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: kickUser, children: [jsxRuntime.jsx(Icon, { icon: "kick-user" }), t('participantView.actionsMenu.kick.label', 'Kick')] }) }), jsxRuntime.jsx(GenericMenuSeparator, {}), jsxRuntime.jsxs(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.MUTE_USERS], children: [hasVideoTrack && (jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: muteVideo, children: [jsxRuntime.jsx(Icon, { icon: "camera-off-outline" }), t('participantView.actionsMenu.turnOffVideo.label', 'Turn off video')] })), hasScreenShareTrack && (jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: muteScreenShare, children: [jsxRuntime.jsx(Icon, { icon: "screen-share-off" }), t('participantView.actionsMenu.turnOffScreenShare.label', 'Turn off screen share')] })), hasAudioTrack && (jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: muteAudio, children: [jsxRuntime.jsx(Icon, { icon: "no-audio" }), t('participantView.actionsMenu.muteAudio.label', 'Mute audio')] })), hasScreenShareAudioTrack && (jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: muteScreenShareAudio, children: [jsxRuntime.jsx(Icon, { icon: "no-audio" }), t('participantView.actionsMenu.muteScreenShareAudio.label', 'Mute screen share audio')] }))] }), participantViewElement &&
|
|
929
|
+
typeof participantViewElement.requestFullscreen !== 'undefined' && (jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: toggleFullscreenMode, children: [jsxRuntime.jsx(Icon, { icon: "fullscreen" }), fullscreenModeOn
|
|
930
|
+
? t('participantView.actionsMenu.leaveFullscreen.label', 'Leave fullscreen')
|
|
931
|
+
: t('participantView.actionsMenu.enterFullscreen.label', 'Enter fullscreen')] })), videoElement && document.pictureInPictureEnabled && (jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: togglePictureInPicture, children: [jsxRuntime.jsx(Icon, { icon: "pip" }), isPiP
|
|
932
|
+
? t('participantView.actionsMenu.leavePip.label', 'Leave picture-in-picture')
|
|
933
|
+
: t('participantView.actionsMenu.enterPip.label', 'Enter picture-in-picture')] })), jsxRuntime.jsx(GenericMenuSeparator, {}), jsxRuntime.jsxs(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.UPDATE_CALL_PERMISSIONS], children: [jsxRuntime.jsx(GenericMenuButtonItem, { onClick: grantPermission(videoClient.OwnCapability.SEND_AUDIO), children: t('participantView.actionsMenu.allowAudio.label', 'Allow audio') }), jsxRuntime.jsx(GenericMenuButtonItem, { onClick: grantPermission(videoClient.OwnCapability.SEND_VIDEO), children: t('participantView.actionsMenu.allowVideo.label', 'Allow video') }), jsxRuntime.jsx(GenericMenuButtonItem, { onClick: grantPermission(videoClient.OwnCapability.SCREENSHARE), children: t('participantView.actionsMenu.allowScreenSharing.label', 'Allow screen sharing') }), jsxRuntime.jsx(GenericMenuButtonItem, { onClick: revokePermission(videoClient.OwnCapability.SEND_AUDIO), children: t('participantView.actionsMenu.disableAudio.label', 'Disable audio') }), jsxRuntime.jsx(GenericMenuButtonItem, { onClick: revokePermission(videoClient.OwnCapability.SEND_VIDEO), children: t('participantView.actionsMenu.disableVideo.label', 'Disable video') }), jsxRuntime.jsx(GenericMenuButtonItem, { onClick: revokePermission(videoClient.OwnCapability.SCREENSHARE), children: t('participantView.actionsMenu.disableScreenSharing.label', 'Disable screen sharing') })] })] }));
|
|
778
934
|
};
|
|
779
935
|
|
|
780
936
|
const isComponentType = (elementOrComponent) => {
|
|
@@ -839,34 +995,39 @@ const BaseVideo = react.forwardRef(function BaseVideoRender({ stream, ...rest },
|
|
|
839
995
|
} }));
|
|
840
996
|
});
|
|
841
997
|
|
|
842
|
-
const
|
|
998
|
+
const variantClasses = ({ size = 'md', showOutline }) => [
|
|
999
|
+
`str-video__avatar--size-${size}`,
|
|
1000
|
+
showOutline && 'str-video__avatar--outlined',
|
|
1001
|
+
];
|
|
1002
|
+
const Avatar = ({ imageSrc, name, style, className, size = 'md', showOutline, ...rest }) => {
|
|
843
1003
|
const [error, setError] = react.useState(false);
|
|
1004
|
+
if (!imageSrc || error) {
|
|
1005
|
+
return name ? (jsxRuntime.jsx(AvatarFallback, { className: className, style: style, names: name.split(/\s+/).filter(Boolean), size: size, showOutline: showOutline })) : null;
|
|
1006
|
+
}
|
|
1007
|
+
return (jsxRuntime.jsx("img", { onError: () => setError(true), alt: "avatar", className: clsx('str-video__avatar', variantClasses({ size, showOutline }), className), src: imageSrc, style: style, ...rest }));
|
|
1008
|
+
};
|
|
1009
|
+
const AvatarFallback = ({ className, names, style, size = 'md', showOutline, }) => {
|
|
1010
|
+
const isCompact = size === 'xs' || size === 'sm';
|
|
1011
|
+
return (jsxRuntime.jsx("div", { className: clsx('str-video__avatar--initials-fallback', variantClasses({ size, showOutline }), className), style: style, children: jsxRuntime.jsxs("div", { children: [names[0]?.[0], !isCompact && names[1]?.[0]] }) }));
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
const BaseVideoPlaceholder = react.forwardRef(function DefaultVideoPlaceholder({ participant, style, children }, ref) {
|
|
844
1015
|
const name = participant.name || participant.userId;
|
|
845
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__video-placeholder", style: style, ref: ref, children: [(
|
|
846
|
-
(name ? (jsxRuntime.jsx(InitialsFallback, { name: name })) : (jsxRuntime.jsx("div", { className: "str-video__video-placeholder__no-video-label", children: children }))), participant.image && !error && (jsxRuntime.jsx("img", { onError: () => setError(true), alt: name, className: "str-video__video-placeholder__avatar", src: participant.image }))] }));
|
|
1016
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__video-placeholder", style: style, ref: ref, children: [(participant.image || name) && (jsxRuntime.jsx(Avatar, { size: "2xl", showOutline: true, imageSrc: participant.image, name: name })), !participant.image && !name && (jsxRuntime.jsx("div", { className: "str-video__video-placeholder__no-video-label", children: children }))] }));
|
|
847
1017
|
});
|
|
848
|
-
const InitialsFallback = (props) => {
|
|
849
|
-
const { name } = props;
|
|
850
|
-
const initials = name
|
|
851
|
-
.split(' ')
|
|
852
|
-
.slice(0, 2)
|
|
853
|
-
.map((n) => n[0])
|
|
854
|
-
.join('');
|
|
855
|
-
return (jsxRuntime.jsx("div", { className: "str-video__video-placeholder__initials-fallback", children: initials }));
|
|
856
|
-
};
|
|
857
1018
|
|
|
858
1019
|
const DefaultVideoPlaceholder = react.forwardRef(function DefaultVideoPlaceholderRender(props, ref) {
|
|
859
|
-
const { t } =
|
|
860
|
-
return (jsxRuntime.jsx(BaseVideoPlaceholder, { ref: ref, ...props, children: t('Video is disabled') }));
|
|
1020
|
+
const { t } = useI18n();
|
|
1021
|
+
return (jsxRuntime.jsx(BaseVideoPlaceholder, { ref: ref, ...props, children: t('common.videoDisabled.text', 'Video is disabled') }));
|
|
861
1022
|
});
|
|
862
1023
|
|
|
863
1024
|
const DefaultPictureInPicturePlaceholder = react.forwardRef(function DefaultPictureInPicturePlaceholderRender(props, ref) {
|
|
864
|
-
const { t } =
|
|
865
|
-
return (jsxRuntime.jsx(BaseVideoPlaceholder, { ref: ref, ...props, children: t('Video is playing in a popup') }));
|
|
1025
|
+
const { t } = useI18n();
|
|
1026
|
+
return (jsxRuntime.jsx(BaseVideoPlaceholder, { ref: ref, ...props, children: t('videoPlaceholder.videoPlayingInPopup.text', 'Video is playing in a popup') }));
|
|
866
1027
|
});
|
|
867
1028
|
|
|
868
1029
|
const ABSOLUTE_POSITION_STYLE = { position: 'absolute' };
|
|
869
|
-
const Video
|
|
1030
|
+
const Video = ({ enabled = true, mirror, trackType, participant, className, VideoPlaceholder = DefaultVideoPlaceholder, PictureInPicturePlaceholder = DefaultPictureInPicturePlaceholder, refs, ...rest }) => {
|
|
870
1031
|
const { sessionId, videoStream, screenShareStream, viewportVisibilityState, isLocalParticipant, userId, } = participant;
|
|
871
1032
|
const call = videoReactBindings.useCall();
|
|
872
1033
|
const [videoElement, setVideoElement] = react.useState(null);
|
|
@@ -940,7 +1101,7 @@ const Video$1 = ({ enabled = true, mirror, trackType, participant, className, Vi
|
|
|
940
1101
|
refs?.setVideoElement?.(element);
|
|
941
1102
|
} })), isPiP && PictureInPicturePlaceholder && (jsxRuntime.jsx(PictureInPicturePlaceholder, { style: ABSOLUTE_POSITION_STYLE, participant: participant })), (hasNoVideoOrInvisible || isVideoPaused) && VideoPlaceholder && (jsxRuntime.jsx(VideoPlaceholder, { style: ABSOLUTE_POSITION_STYLE, participant: participant, ref: refs?.setVideoPlaceholderElement }))] }));
|
|
942
1103
|
};
|
|
943
|
-
Video
|
|
1104
|
+
Video.displayName = 'Video';
|
|
944
1105
|
|
|
945
1106
|
const useTrackElementVisibility = ({ trackedElement, sessionId, trackType, }) => {
|
|
946
1107
|
const call = videoReactBindings.useCall();
|
|
@@ -951,14 +1112,6 @@ const useTrackElementVisibility = ({ trackedElement, sessionId, trackType, }) =>
|
|
|
951
1112
|
}, [trackedElement, call, sessionId, trackType]);
|
|
952
1113
|
};
|
|
953
1114
|
|
|
954
|
-
const Avatar = ({ imageSrc, name, style, className, ...rest }) => {
|
|
955
|
-
const [error, setError] = react.useState(false);
|
|
956
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(!imageSrc || error) && name && (jsxRuntime.jsx(AvatarFallback, { className: className, style: style, names: [name] })), imageSrc && !error && (jsxRuntime.jsx("img", { onError: () => setError(true), alt: "avatar", className: clsx('str-video__avatar', className), src: imageSrc, style: style, ...rest }))] }));
|
|
957
|
-
};
|
|
958
|
-
const AvatarFallback = ({ className, names, style, }) => {
|
|
959
|
-
return (jsxRuntime.jsx("div", { className: clsx('str-video__avatar--initials-fallback', className), style: style, children: jsxRuntime.jsxs("div", { children: [names[0][0], names[1]?.[0]] }) }));
|
|
960
|
-
};
|
|
961
|
-
|
|
962
1115
|
const BackgroundFiltersProviderImpl = react.lazy(() => Promise.resolve().then(function () { return require('./background-filters-DMStbSEg.cjs.js'); }).then((m) => ({
|
|
963
1116
|
default: m.BackgroundFiltersProvider,
|
|
964
1117
|
})));
|
|
@@ -987,40 +1140,36 @@ const BackgroundFiltersProvider = (props) => {
|
|
|
987
1140
|
return (jsxRuntime.jsx(react.Suspense, { fallback: SuspenseFallback, children: jsxRuntime.jsx(BackgroundFiltersProviderImpl, { ...filterProps, ContextProvider: BackgroundFiltersContext }) }));
|
|
988
1141
|
};
|
|
989
1142
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1143
|
+
/**
|
|
1144
|
+
* A compact badge for counts, notifications and error markers.
|
|
1145
|
+
*
|
|
1146
|
+
* Without `icon` it is a pill that grows with its content; with `icon` it is a
|
|
1147
|
+
* circle of the size given by `size`.
|
|
1148
|
+
*
|
|
1149
|
+
* The badge carries no positioning of its own — whatever it annotates places
|
|
1150
|
+
* it. For the call controls, rendering a badge among `CompositeButton`'s
|
|
1151
|
+
* children anchors it to the top-right corner of the button.
|
|
1152
|
+
*/
|
|
1153
|
+
const Badge = react.forwardRef(function BadgeRender({ variant = 'default', size = 'sm', icon, className, children, ...rest }, ref) {
|
|
1154
|
+
return (jsxRuntime.jsx("span", { ref: ref, className: clsx('str-video__badge', `str-video__badge--${variant}`, `str-video__badge--size-${size}`, icon && 'str-video__badge--icon', className), ...rest, children: icon ? jsxRuntime.jsx(Icon, { icon: icon }) : children }));
|
|
999
1155
|
});
|
|
1000
1156
|
|
|
1001
|
-
const
|
|
1002
|
-
return (jsxRuntime.
|
|
1003
|
-
'str-video__composite-button--caption': caption,
|
|
1004
|
-
'str-video__composite-button--menu': Menu,
|
|
1005
|
-
}), title: title, ref: ref, children: [jsxRuntime.jsxs("div", { className: clsx('str-video__composite-button__button-group', {
|
|
1006
|
-
'str-video__composite-button__button-group--active': active,
|
|
1007
|
-
'str-video__composite-button__button-group--active-primary': active && variant === 'primary',
|
|
1008
|
-
'str-video__composite-button__button-group--active-secondary': active && variant === 'secondary',
|
|
1009
|
-
'str-video__composite-button__button-group--disabled': disabled,
|
|
1010
|
-
}), children: [jsxRuntime.jsx("button", { type: "button", className: "str-video__composite-button__button", onClick: (e) => {
|
|
1011
|
-
e.preventDefault();
|
|
1012
|
-
onClick?.(e);
|
|
1013
|
-
}, disabled: disabled, ...restButtonProps, children: children }), Menu && (jsxRuntime.jsx(MenuToggle, { offset: menuOffset, placement: menuPlacement, ToggleButton: ToggleMenuButton, onToggle: onMenuToggle, children: isComponentType(Menu) ? jsxRuntime.jsx(Menu, {}) : Menu }))] }), caption && (jsxRuntime.jsx("div", { className: "str-video__composite-button__caption", children: caption }))] }));
|
|
1157
|
+
const Button = react.forwardRef(function ButtonRender({ variant = 'primary', appearance = 'solid', size = 'md', active, className, type = 'button', children, ...rest }, ref) {
|
|
1158
|
+
return (jsxRuntime.jsx("button", { ref: ref, type: type, className: clsx('str-video__button', `str-video__button--${variant}`, `str-video__button--${appearance}`, `str-video__button--size-${size}`, className), ...rest, "aria-pressed": active ?? rest['aria-pressed'], children: children }));
|
|
1014
1159
|
});
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
}), icon: menuShown ? 'caret-down' : 'caret-up', ref: ref }));
|
|
1160
|
+
|
|
1161
|
+
const IconButton = react.forwardRef(function IconButtonRender({ icon, className, ...props }, ref) {
|
|
1162
|
+
return (jsxRuntime.jsx(Button, { ref: ref, className: clsx('str-video__button--icon-only', className), ...props, children: jsxRuntime.jsx(Icon, { icon: icon }) }));
|
|
1019
1163
|
});
|
|
1020
1164
|
|
|
1021
|
-
const
|
|
1022
|
-
return (jsxRuntime.
|
|
1023
|
-
};
|
|
1165
|
+
const CompositeButton = react.forwardRef(function CompositeButtonRender({ appearance, caption, children, className, disabled, Menu, menuOffset, menuPlacement, onMenuToggle, active, size = 'md', title, ToggleMenuButton = CompositeCaret, variant = 'secondary', ...buttonProps }, ref) {
|
|
1166
|
+
return (jsxRuntime.jsxs("div", { ref: ref, title: title, className: clsx('str-video__composite-button', `str-video__composite-button--${variant}`, `str-video__composite-button--size-${size}`, `str-video__composite-button--${appearance ?? 'solid'}`, Menu && 'str-video__composite-button--menu', className), children: [jsxRuntime.jsxs("div", { className: "str-video__composite-button__group", children: [jsxRuntime.jsx(Button, { variant: variant, appearance: appearance, size: size, disabled: disabled, active: active, className: "str-video__composite-button__action str-video__button--icon-only", ...buttonProps, children: children }), Menu &&
|
|
1167
|
+
(disabled ? (jsxRuntime.jsx(CompositeCaret, { menuShown: false, disabled: true })) : (jsxRuntime.jsx(MenuToggle, { offset: menuOffset, placement: menuPlacement, ToggleButton: ToggleMenuButton, onToggle: onMenuToggle, children: isComponentType(Menu) ? jsxRuntime.jsx(Menu, {}) : Menu })))] }), caption && (jsxRuntime.jsx("span", { className: "str-video__composite-button__caption", children: caption }))] }));
|
|
1168
|
+
});
|
|
1169
|
+
const CompositeCaret = react.forwardRef(function CompositeCaretRender({ menuShown, disabled }, ref) {
|
|
1170
|
+
const { t } = useI18n();
|
|
1171
|
+
return (jsxRuntime.jsx(IconButton, { className: "str-video__composite-button__caret", size: "xs", appearance: "ghost", disabled: disabled, "aria-label": t('common.toggleMenu.ariaLabel', 'Toggle menu'), "aria-haspopup": "menu", "aria-expanded": menuShown, icon: menuShown ? 'caret-down' : 'caret-up', ref: ref }));
|
|
1172
|
+
});
|
|
1024
1173
|
|
|
1025
1174
|
const AcceptCallButton = ({ disabled, onAccept, onClick, }) => {
|
|
1026
1175
|
const call = videoReactBindings.useCall();
|
|
@@ -1039,11 +1188,16 @@ const AcceptCallButton = ({ disabled, onAccept, onClick, }) => {
|
|
|
1039
1188
|
}
|
|
1040
1189
|
}
|
|
1041
1190
|
}, [onClick, onAccept, call]);
|
|
1042
|
-
return (jsxRuntime.jsx(IconButton, { disabled: disabled, icon: "call-accept", variant: "
|
|
1191
|
+
return (jsxRuntime.jsx(IconButton, { className: "str-video__accept-call-button", size: "sm", disabled: disabled, icon: "call-accept", variant: "secondary", "data-testid": "accept-call-button", onClick: handleClick }));
|
|
1043
1192
|
};
|
|
1044
1193
|
|
|
1194
|
+
const ICON_BY_STATE = {
|
|
1195
|
+
success: 'checkmark',
|
|
1196
|
+
error: 'exclamation-circle-fill',
|
|
1197
|
+
loading: 'loading',
|
|
1198
|
+
};
|
|
1045
1199
|
const Notification = (props) => {
|
|
1046
|
-
const { isVisible, message, children, visibilityTimeout, resetIsVisible, placement = 'top', className,
|
|
1200
|
+
const { isVisible, message, children, visibilityTimeout, resetIsVisible, placement = 'top', className, state, close, } = props;
|
|
1047
1201
|
const { refs, x, y, strategy } = useFloatingUIPreset({
|
|
1048
1202
|
placement,
|
|
1049
1203
|
strategy: 'absolute',
|
|
@@ -1056,12 +1210,13 @@ const Notification = (props) => {
|
|
|
1056
1210
|
}, visibilityTimeout);
|
|
1057
1211
|
return () => clearTimeout(timeout);
|
|
1058
1212
|
}, [isVisible, resetIsVisible, visibilityTimeout]);
|
|
1059
|
-
|
|
1213
|
+
const icon = state && `str-video__icon str-video__icon--${ICON_BY_STATE[state]}`;
|
|
1214
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__notification-wrapper", ref: refs.setReference, children: [isVisible && (jsxRuntime.jsxs("div", { className: clsx('str-video__notification', state && `str-video__notification--${state}`, close && 'str-video__notification--dismissible', className), ref: refs.setFloating, style: {
|
|
1060
1215
|
position: strategy,
|
|
1061
1216
|
top: y ?? 0,
|
|
1062
1217
|
left: x ?? 0,
|
|
1063
1218
|
overflowY: 'auto',
|
|
1064
|
-
}, children: [
|
|
1219
|
+
}, children: [icon && jsxRuntime.jsx("i", { className: icon }), jsxRuntime.jsx("span", { className: "str-video__notification__message", children: message }), close ? (jsxRuntime.jsx("i", { className: "str-video__icon str-video__icon--close str-video__notification__close", onClick: close })) : null] })), children] }));
|
|
1065
1220
|
};
|
|
1066
1221
|
|
|
1067
1222
|
const PermissionNotification = (props) => {
|
|
@@ -1084,24 +1239,26 @@ const PermissionNotification = (props) => {
|
|
|
1084
1239
|
}, [hasPermission]);
|
|
1085
1240
|
const resetIsVisible = react.useCallback(() => setShowNotification(undefined), []);
|
|
1086
1241
|
if (isAwaitingApproval) {
|
|
1087
|
-
return (jsxRuntime.jsx(Notification, { isVisible: isAwaitingApproval && !hasPermission, message: messageAwaitingApproval, children: children }));
|
|
1242
|
+
return (jsxRuntime.jsx(Notification, { state: "loading", isVisible: isAwaitingApproval && !hasPermission, message: messageAwaitingApproval, children: children }));
|
|
1088
1243
|
}
|
|
1089
|
-
return (jsxRuntime.jsx(Notification, { isVisible: !!showNotification, visibilityTimeout: visibilityTimeout, resetIsVisible: resetIsVisible, message: showNotification === 'granted' ? messageApproved : messageRevoked, children: children }));
|
|
1244
|
+
return (jsxRuntime.jsx(Notification, { state: showNotification === 'granted' ? 'success' : 'error', isVisible: !!showNotification, visibilityTimeout: visibilityTimeout, resetIsVisible: resetIsVisible, message: showNotification === 'granted' ? messageApproved : messageRevoked, children: children }));
|
|
1090
1245
|
};
|
|
1091
1246
|
|
|
1092
1247
|
const SpeakingWhileMutedNotification = ({ children, text, placement, }) => {
|
|
1093
1248
|
const { useMicrophoneState } = videoReactBindings.useCallStateHooks();
|
|
1094
1249
|
const { isSpeakingWhileMuted } = useMicrophoneState();
|
|
1095
|
-
const { t } =
|
|
1096
|
-
const message = text ??
|
|
1250
|
+
const { t } = useI18n();
|
|
1251
|
+
const message = text ??
|
|
1252
|
+
t('notification.speakingWhileMuted.text', 'You are muted. Unmute to speak.');
|
|
1097
1253
|
return (jsxRuntime.jsx(Notification, { message: message, isVisible: isSpeakingWhileMuted, placement: placement || 'top-start', children: children }));
|
|
1098
1254
|
};
|
|
1099
1255
|
|
|
1100
1256
|
const RecordingInProgressNotification = ({ children, text, }) => {
|
|
1101
|
-
const { t } =
|
|
1257
|
+
const { t } = useI18n();
|
|
1102
1258
|
const { isCallRecordingInProgress } = videoReactBindings.useToggleCallRecording();
|
|
1103
1259
|
const [isVisible, setVisible] = react.useState(false);
|
|
1104
|
-
const message = text ??
|
|
1260
|
+
const message = text ??
|
|
1261
|
+
t('notification.recordingInProgress.text', 'Recording in progress...');
|
|
1105
1262
|
react.useEffect(() => {
|
|
1106
1263
|
if (isCallRecordingInProgress) {
|
|
1107
1264
|
setVisible(true);
|
|
@@ -1110,12 +1267,12 @@ const RecordingInProgressNotification = ({ children, text, }) => {
|
|
|
1110
1267
|
setVisible(false);
|
|
1111
1268
|
}
|
|
1112
1269
|
}, [isCallRecordingInProgress]);
|
|
1113
|
-
return (jsxRuntime.jsx(Notification, { message: message,
|
|
1270
|
+
return (jsxRuntime.jsx(Notification, { message: message, isVisible: isVisible, placement: "top-start", close: () => setVisible(false), children: children }));
|
|
1114
1271
|
};
|
|
1115
1272
|
|
|
1116
1273
|
const MicCaptureErrorNotification = ({ children, text, placement, }) => {
|
|
1117
1274
|
const call = videoReactBindings.useCall();
|
|
1118
|
-
const { t } =
|
|
1275
|
+
const { t } = useI18n();
|
|
1119
1276
|
const [isVisible, setIsVisible] = react.useState(false);
|
|
1120
1277
|
react.useEffect(() => {
|
|
1121
1278
|
if (!call)
|
|
@@ -1125,8 +1282,8 @@ const MicCaptureErrorNotification = ({ children, text, placement, }) => {
|
|
|
1125
1282
|
});
|
|
1126
1283
|
}, [call]);
|
|
1127
1284
|
const message = text ??
|
|
1128
|
-
t('Your microphone is not capturing audio. Please check your setup.');
|
|
1129
|
-
return (jsxRuntime.jsx(Notification, { message: message, isVisible: isVisible, placement: placement, close: () => setIsVisible(false), children: children }));
|
|
1285
|
+
t('notification.micCaptureError.text', 'Your microphone is not capturing audio. Please check your setup.');
|
|
1286
|
+
return (jsxRuntime.jsx(Notification, { message: message, state: "error", isVisible: isVisible, placement: placement, close: () => setIsVisible(false), children: children }));
|
|
1130
1287
|
};
|
|
1131
1288
|
|
|
1132
1289
|
const LoadingIndicator = ({ className, type = 'spinner', text, tooltip, }) => {
|
|
@@ -1134,22 +1291,20 @@ const LoadingIndicator = ({ className, type = 'spinner', text, tooltip, }) => {
|
|
|
1134
1291
|
};
|
|
1135
1292
|
|
|
1136
1293
|
const Tooltip = ({ children, referenceElement, tooltipClassName, tooltipPlacement = 'top', visible = false, }) => {
|
|
1137
|
-
const
|
|
1138
|
-
const { refs, x, y, strategy, context } = useFloatingUIPreset({
|
|
1294
|
+
const { refs, x, y, strategy } = useFloatingUIPreset({
|
|
1139
1295
|
placement: tooltipPlacement,
|
|
1140
1296
|
strategy: 'absolute',
|
|
1141
|
-
middleware: [react$1.arrow({ element: arrowRef })],
|
|
1142
1297
|
});
|
|
1143
1298
|
react.useEffect(() => {
|
|
1144
1299
|
refs.setReference(referenceElement);
|
|
1145
1300
|
}, [referenceElement, refs]);
|
|
1146
1301
|
if (!visible)
|
|
1147
1302
|
return null;
|
|
1148
|
-
return (jsxRuntime.
|
|
1303
|
+
return (jsxRuntime.jsx("div", { className: clsx('str-video__tooltip', tooltipClassName), ref: refs.setFloating, style: {
|
|
1149
1304
|
position: strategy,
|
|
1150
1305
|
top: y ?? 0,
|
|
1151
1306
|
left: x ?? 0,
|
|
1152
|
-
}, children:
|
|
1307
|
+
}, children: children }));
|
|
1153
1308
|
};
|
|
1154
1309
|
|
|
1155
1310
|
const useEnterLeaveHandlers = ({ onMouseEnter, onMouseLeave, } = {}) => {
|
|
@@ -1201,18 +1356,18 @@ function isNotAllowedError(error) {
|
|
|
1201
1356
|
}
|
|
1202
1357
|
|
|
1203
1358
|
const RecordEndConfirmation = (props) => {
|
|
1204
|
-
const { t } =
|
|
1359
|
+
const { t } = useI18n();
|
|
1205
1360
|
const { toggleCallRecording, isAwaitingResponse } = videoReactBindings.useToggleCallRecording();
|
|
1206
1361
|
const { close } = useMenuContext();
|
|
1207
1362
|
const handleClick = createCallControlHandler(props, toggleCallRecording);
|
|
1208
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__end-recording__confirmation", children: [jsxRuntime.jsxs("div", { className: "str-video__end-recording__header", children: [jsxRuntime.jsx(Icon, { icon: "recording-on" }), jsxRuntime.jsx("h2", { className: "str-video__end-recording__heading", children: t('End recording') })
|
|
1363
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__end-recording__confirmation", children: [jsxRuntime.jsxs("div", { className: "str-video__end-recording__header", children: [jsxRuntime.jsx(Icon, { icon: "recording-on" }), jsxRuntime.jsxs("div", { className: "str-video__end-recording__text", children: [jsxRuntime.jsx("h2", { className: "str-video__end-recording__heading", children: t('callControls.recordCallButton.endRecording.title', 'End recording') }), jsxRuntime.jsx("p", { className: "str-video__end-recording__description", children: t('callControls.recordCallButton.confirmEndRecording.description', 'Are you sure you want end the recording?') })] })] }), jsxRuntime.jsxs("div", { className: "str-video__end-recording__actions", children: [jsxRuntime.jsx(Button, { variant: "destructive", onClick: isAwaitingResponse ? undefined : handleClick, children: isAwaitingResponse ? (jsxRuntime.jsx(LoadingIndicator, {})) : (t('callControls.recordCallButton.endRecording.title', 'End recording')) }), jsxRuntime.jsx(Button, { variant: "secondary", appearance: "outline", onClick: close, children: t('common.cancel.label', 'Cancel') })] })] }));
|
|
1209
1364
|
};
|
|
1210
1365
|
const ToggleEndRecordingMenuButton = react.forwardRef(function ToggleEndRecordingMenuButtonRender(props, ref) {
|
|
1211
|
-
return (jsxRuntime.jsx(CompositeButton, { ref: ref, active: true, variant: "
|
|
1366
|
+
return (jsxRuntime.jsx(CompositeButton, { ref: ref, active: true, variant: "destructive", "data-testid": "recording-stop-button", children: jsxRuntime.jsx(Icon, { icon: "recording-off" }) }));
|
|
1212
1367
|
});
|
|
1213
1368
|
const RecordCallConfirmationButton = (props) => {
|
|
1214
1369
|
const { caption } = props;
|
|
1215
|
-
const { t } =
|
|
1370
|
+
const { t } = useI18n();
|
|
1216
1371
|
const { toggleCallRecording, isAwaitingResponse, isCallRecordingInProgress } = videoReactBindings.useToggleCallRecording();
|
|
1217
1372
|
const handleClick = createCallControlHandler(props, toggleCallRecording);
|
|
1218
1373
|
if (isCallRecordingInProgress) {
|
|
@@ -1222,28 +1377,30 @@ const RecordCallConfirmationButton = (props) => {
|
|
|
1222
1377
|
], children: jsxRuntime.jsx(MenuToggle, { ToggleButton: ToggleEndRecordingMenuButton, visualType: exports.MenuVisualType.PORTAL, children: jsxRuntime.jsx(RecordEndConfirmation, { onError: props.onError }) }) }));
|
|
1223
1378
|
}
|
|
1224
1379
|
const title = isAwaitingResponse
|
|
1225
|
-
? t('Waiting for recording to start...')
|
|
1226
|
-
: (caption ??
|
|
1380
|
+
? t('callControls.recordCallButton.waitingRecordingStart.title', 'Waiting for recording to start...')
|
|
1381
|
+
: (caption ??
|
|
1382
|
+
t('callControls.recordCallButton.recordCall.title', 'Record call'));
|
|
1227
1383
|
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [
|
|
1228
1384
|
videoClient.OwnCapability.START_RECORD_CALL,
|
|
1229
1385
|
videoClient.OwnCapability.STOP_RECORD_CALL,
|
|
1230
|
-
], children: jsxRuntime.jsx(WithTooltip, { title: title, children: jsxRuntime.jsx(CompositeButton, { active: isCallRecordingInProgress, caption: caption, variant:
|
|
1386
|
+
], children: jsxRuntime.jsx(WithTooltip, { title: title, children: jsxRuntime.jsx(CompositeButton, { active: isCallRecordingInProgress, caption: caption, variant: isCallRecordingInProgress ? 'destructive' : 'secondary', "data-testid": "recording-start-button", onClick: isAwaitingResponse ? undefined : handleClick, children: isAwaitingResponse ? (jsxRuntime.jsx(LoadingIndicator, {})) : (jsxRuntime.jsx(Icon, { icon: "recording-off" })) }) }) }));
|
|
1231
1387
|
};
|
|
1232
1388
|
const RecordCallButton = (props) => {
|
|
1233
1389
|
const { caption } = props;
|
|
1234
|
-
const { t } =
|
|
1390
|
+
const { t } = useI18n();
|
|
1235
1391
|
const { toggleCallRecording, isAwaitingResponse, isCallRecordingInProgress } = videoReactBindings.useToggleCallRecording();
|
|
1236
1392
|
const handleClick = createCallControlHandler(props, toggleCallRecording);
|
|
1237
|
-
let title = caption ??
|
|
1393
|
+
let title = caption ??
|
|
1394
|
+
t('callControls.recordCallButton.recordCall.title', 'Record call');
|
|
1238
1395
|
if (isAwaitingResponse) {
|
|
1239
1396
|
title = isCallRecordingInProgress
|
|
1240
|
-
? t('Waiting for recording to stop...')
|
|
1241
|
-
: t('Waiting for recording to start...');
|
|
1397
|
+
? t('callControls.recordCallButton.waitingRecordingStop.title', 'Waiting for recording to stop...')
|
|
1398
|
+
: t('callControls.recordCallButton.waitingRecordingStart.title', 'Waiting for recording to start...');
|
|
1242
1399
|
}
|
|
1243
1400
|
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [
|
|
1244
1401
|
videoClient.OwnCapability.START_RECORD_CALL,
|
|
1245
1402
|
videoClient.OwnCapability.STOP_RECORD_CALL,
|
|
1246
|
-
], children: jsxRuntime.jsx(CompositeButton, { active: isCallRecordingInProgress, caption: caption, variant:
|
|
1403
|
+
], children: jsxRuntime.jsx(CompositeButton, { active: isCallRecordingInProgress, caption: caption, variant: isCallRecordingInProgress ? 'destructive' : 'secondary', "data-testid": isCallRecordingInProgress
|
|
1247
1404
|
? 'recording-stop-button'
|
|
1248
1405
|
: 'recording-start-button', title: title, onClick: isAwaitingResponse ? undefined : handleClick, children: isAwaitingResponse ? (jsxRuntime.jsx(LoadingIndicator, {})) : (jsxRuntime.jsx(Icon, { icon: isCallRecordingInProgress ? 'recording-on' : 'recording-off' })) }) }));
|
|
1249
1406
|
};
|
|
@@ -1305,8 +1462,8 @@ const ReactionsButton = ({ reactions = defaultReactions, }) => {
|
|
|
1305
1462
|
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx(MenuToggle, { placement: "top", ToggleButton: ToggleReactionsMenuButton, visualType: exports.MenuVisualType.MENU, children: jsxRuntime.jsx(DefaultReactionsMenu, { reactions: reactions }) }) }));
|
|
1306
1463
|
};
|
|
1307
1464
|
const ToggleReactionsMenuButton = react.forwardRef(function ToggleReactionsMenuButtonRender({ menuShown }, ref) {
|
|
1308
|
-
const { t } =
|
|
1309
|
-
return (jsxRuntime.jsx(WithTooltip, { title: t('Reactions'), tooltipDisabled: menuShown, children: jsxRuntime.jsx(CompositeButton, { ref: ref, active: menuShown,
|
|
1465
|
+
const { t } = useI18n();
|
|
1466
|
+
return (jsxRuntime.jsx(WithTooltip, { title: t('callControls.reactionsButton.reactions.title', 'Reactions'), tooltipDisabled: menuShown, children: jsxRuntime.jsx(CompositeButton, { ref: ref, active: menuShown, children: jsxRuntime.jsx(Icon, { icon: "reactions" }) }) }));
|
|
1310
1467
|
});
|
|
1311
1468
|
const DefaultReactionsMenu = ({ reactions, layout = 'horizontal', }) => {
|
|
1312
1469
|
const call = videoReactBindings.useCall();
|
|
@@ -1321,7 +1478,7 @@ const DefaultReactionsMenu = ({ reactions, layout = 'horizontal', }) => {
|
|
|
1321
1478
|
};
|
|
1322
1479
|
|
|
1323
1480
|
const ScreenShareButton = (props) => {
|
|
1324
|
-
const { t } =
|
|
1481
|
+
const { t } = useI18n();
|
|
1325
1482
|
const { caption, optimisticUpdates } = props;
|
|
1326
1483
|
const { useHasOngoingScreenShare, useScreenShareState, useCallSettings } = videoReactBindings.useCallStateHooks();
|
|
1327
1484
|
const isSomeoneScreenSharing = useHasOngoingScreenShare();
|
|
@@ -1343,7 +1500,10 @@ const ScreenShareButton = (props) => {
|
|
|
1343
1500
|
await screenShare.toggle();
|
|
1344
1501
|
}
|
|
1345
1502
|
});
|
|
1346
|
-
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SCREENSHARE], children: jsxRuntime.jsx(PermissionNotification, { permission: videoClient.OwnCapability.SCREENSHARE, isAwaitingApproval: isAwaitingPermission, messageApproved: t('You can now share your screen.'), messageAwaitingApproval: t('Awaiting for an approval to share screen.'), messageRevoked: t('You can no longer share your screen.'), children: jsxRuntime.jsx(WithTooltip, { title: caption ??
|
|
1503
|
+
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SCREENSHARE], children: jsxRuntime.jsx(PermissionNotification, { permission: videoClient.OwnCapability.SCREENSHARE, isAwaitingApproval: isAwaitingPermission, messageApproved: t('callControls.screenShareButton.permissionGranted.text', 'You can now share your screen.'), messageAwaitingApproval: t('callControls.screenShareButton.awaitingApproval.text', 'Awaiting for an approval to share screen.'), messageRevoked: t('callControls.screenShareButton.permissionRevoked.text', 'You can no longer share your screen.'), children: jsxRuntime.jsx(WithTooltip, { title: caption ??
|
|
1504
|
+
t('callControls.screenShareButton.shareScreen.title', 'Share screen'), children: jsxRuntime.jsx(CompositeButton, { active: isSomeoneScreenSharing || amIScreenSharing, caption: caption, variant: isSomeoneScreenSharing || amIScreenSharing
|
|
1505
|
+
? 'primary'
|
|
1506
|
+
: 'secondary', "data-testid": isSomeoneScreenSharing
|
|
1347
1507
|
? 'screen-share-stop-button'
|
|
1348
1508
|
: 'screen-share-start-button', disabled: disableScreenShareButton, onClick: handleClick, children: jsxRuntime.jsx(Icon, { icon: isSomeoneScreenSharing ? 'screen-share-on' : 'screen-share-off' }) }) }) }) }));
|
|
1349
1509
|
};
|
|
@@ -1399,7 +1559,7 @@ const DeviceLevelIndicator = ({ deviceId }) => {
|
|
|
1399
1559
|
const DeviceAudioPreviewItem = ({ device, onSelect, }) => {
|
|
1400
1560
|
if (device.deviceId === 'default')
|
|
1401
1561
|
return null;
|
|
1402
|
-
return (jsxRuntime.jsxs("label", { className: `str-video__device-settings__option${device.isSelected ? ' str-video__device-settings__option--selected' : ''}`, htmlFor: `audioinput--${device.deviceId}`, children: [jsxRuntime.jsx("input", { type: "radio", name: "audioinput", value: device.deviceId, id: `audioinput--${device.deviceId}`, checked: device.isSelected, onChange: (e) => onSelect(e.target.value) }), device.label, jsxRuntime.jsx(DeviceLevelIndicator, { deviceId: device.deviceId })] }));
|
|
1562
|
+
return (jsxRuntime.jsxs("label", { className: `str-video__device-settings__option${device.isSelected ? ' str-video__device-settings__option--selected' : ''}`, htmlFor: `audioinput--${device.deviceId}`, children: [jsxRuntime.jsx("input", { type: "radio", name: "audioinput", value: device.deviceId, id: `audioinput--${device.deviceId}`, checked: device.isSelected, onChange: (e) => onSelect(e.target.value) }), jsxRuntime.jsx("span", { className: "str-video__device-settings__option__label", children: device.label }), jsxRuntime.jsx(DeviceLevelIndicator, { deviceId: device.deviceId })] }));
|
|
1403
1563
|
};
|
|
1404
1564
|
|
|
1405
1565
|
const SelectContext = react.createContext({});
|
|
@@ -1409,12 +1569,12 @@ const Select = (props) => {
|
|
|
1409
1569
|
const [activeIndex, setActiveIndex] = react.useState(null);
|
|
1410
1570
|
const [selectedIndex, setSelectedIndex] = react.useState(defaultSelectedIndex);
|
|
1411
1571
|
const [selectedLabel, setSelectedLabel] = react.useState(defaultSelectedLabel);
|
|
1412
|
-
const { refs, context } = react$
|
|
1572
|
+
const { refs, context } = react$2.useFloating({
|
|
1413
1573
|
placement: 'bottom-start',
|
|
1414
1574
|
open: isOpen,
|
|
1415
1575
|
onOpenChange: setIsOpen,
|
|
1416
|
-
whileElementsMounted: react$
|
|
1417
|
-
middleware: [react$
|
|
1576
|
+
whileElementsMounted: react$2.autoUpdate,
|
|
1577
|
+
middleware: [react$2.flip()],
|
|
1418
1578
|
});
|
|
1419
1579
|
const elementsRef = react.useRef([]);
|
|
1420
1580
|
const labelsRef = react.useRef([]);
|
|
@@ -1434,34 +1594,34 @@ const Select = (props) => {
|
|
|
1434
1594
|
handleSelect(index);
|
|
1435
1595
|
}
|
|
1436
1596
|
};
|
|
1437
|
-
const listNav = react$
|
|
1597
|
+
const listNav = react$2.useListNavigation(context, {
|
|
1438
1598
|
listRef: elementsRef,
|
|
1439
1599
|
activeIndex,
|
|
1440
1600
|
selectedIndex,
|
|
1441
1601
|
onNavigate: setActiveIndex,
|
|
1442
1602
|
});
|
|
1443
|
-
const typeahead = react$
|
|
1603
|
+
const typeahead = react$2.useTypeahead(context, {
|
|
1444
1604
|
listRef: labelsRef,
|
|
1445
1605
|
activeIndex,
|
|
1446
1606
|
selectedIndex,
|
|
1447
1607
|
onMatch: handleTypeaheadMatch,
|
|
1448
1608
|
});
|
|
1449
|
-
const click = react$
|
|
1450
|
-
const dismiss = react$
|
|
1451
|
-
const role = react$
|
|
1452
|
-
const { getReferenceProps, getFloatingProps, getItemProps } = react$
|
|
1609
|
+
const click = react$2.useClick(context);
|
|
1610
|
+
const dismiss = react$2.useDismiss(context);
|
|
1611
|
+
const role = react$2.useRole(context, { role: 'listbox' });
|
|
1612
|
+
const { getReferenceProps, getFloatingProps, getItemProps } = react$2.useInteractions([listNav, typeahead, click, dismiss, role]);
|
|
1453
1613
|
const selectContext = react.useMemo(() => ({
|
|
1454
1614
|
activeIndex,
|
|
1455
1615
|
selectedIndex,
|
|
1456
1616
|
getItemProps,
|
|
1457
1617
|
handleSelect,
|
|
1458
1618
|
}), [activeIndex, selectedIndex, getItemProps, handleSelect]);
|
|
1459
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__dropdown", children: [jsxRuntime.jsxs("div", { className: "str-video__dropdown-selected", ref: refs.setReference, tabIndex: 0, ...getReferenceProps(), children: [jsxRuntime.jsxs("label", { className: "str-video__dropdown-selected__label", children: [icon && (jsxRuntime.jsx(Icon, { className: "str-video__dropdown-selected__icon", icon: icon })), selectedLabel] }), jsxRuntime.jsx(Icon, { className: "str-video__dropdown-selected__chevron", icon: isOpen ? 'chevron-up' : 'chevron-down' })] }), jsxRuntime.jsx(SelectContext.Provider, { value: selectContext, children: isOpen && (jsxRuntime.jsx(react$
|
|
1619
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__dropdown", children: [jsxRuntime.jsxs("div", { className: "str-video__dropdown-selected", ref: refs.setReference, tabIndex: 0, ...getReferenceProps(), children: [jsxRuntime.jsxs("label", { className: "str-video__dropdown-selected__label", children: [icon && (jsxRuntime.jsx(Icon, { className: "str-video__dropdown-selected__icon", icon: icon })), jsxRuntime.jsx("span", { className: "str-video__dropdown-selected__text", children: selectedLabel })] }), jsxRuntime.jsx(Icon, { className: "str-video__dropdown-selected__chevron", icon: isOpen ? 'chevron-up' : 'chevron-down' })] }), jsxRuntime.jsx(SelectContext.Provider, { value: selectContext, children: isOpen && (jsxRuntime.jsx(react$2.FloatingFocusManager, { context: context, modal: false, children: jsxRuntime.jsx("div", { className: "str-video__dropdown-list", ref: refs.setFloating, ...getFloatingProps(), children: jsxRuntime.jsx(react$2.FloatingList, { elementsRef: elementsRef, labelsRef: labelsRef, children: children }) }) })) })] }));
|
|
1460
1620
|
};
|
|
1461
1621
|
const DropDownSelectOption = (props) => {
|
|
1462
1622
|
const { selected, label, icon } = props;
|
|
1463
1623
|
const { getItemProps, handleSelect } = react.useContext(SelectContext);
|
|
1464
|
-
const { ref, index } = react$
|
|
1624
|
+
const { ref, index } = react$2.useListItem();
|
|
1465
1625
|
return (jsxRuntime.jsxs("div", { className: clsx('str-video__dropdown-option', {
|
|
1466
1626
|
'str-video__dropdown-option--selected': selected,
|
|
1467
1627
|
}), ref: ref, ...getItemProps({
|
|
@@ -1477,7 +1637,7 @@ const DeviceSelectorOption = ({ disabled, id, label, onChange, name, selected, d
|
|
|
1477
1637
|
return (jsxRuntime.jsxs("label", { className: clsx('str-video__device-settings__option', {
|
|
1478
1638
|
'str-video__device-settings__option--selected': selected,
|
|
1479
1639
|
'str-video__device-settings__option--disabled': disabled,
|
|
1480
|
-
}), htmlFor: id, children: [jsxRuntime.jsx("input", { type: "radio", name: name, onChange: onChange, value: value, id: id, checked: selected, defaultChecked: defaultChecked, disabled: disabled }), label] }));
|
|
1640
|
+
}), htmlFor: id, children: [jsxRuntime.jsx("input", { type: "radio", name: name, onChange: onChange, value: value, id: id, checked: selected, defaultChecked: defaultChecked, disabled: disabled }), jsxRuntime.jsx("span", { className: "str-video__device-settings__option__label", children: label })] }));
|
|
1481
1641
|
};
|
|
1482
1642
|
const DeviceSelectorList = (props) => {
|
|
1483
1643
|
const { devices = [], selectedDeviceId, title, type, onChange, children, } = props;
|
|
@@ -1537,8 +1697,8 @@ const SpeakerTest = (props) => {
|
|
|
1537
1697
|
const { selectedDevice } = useSpeakerState();
|
|
1538
1698
|
const audioElementRef = react.useRef(null);
|
|
1539
1699
|
const [isPlaying, setIsPlaying] = react.useState(false);
|
|
1540
|
-
const { t } =
|
|
1541
|
-
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"2.0.0-beta.
|
|
1700
|
+
const { t } = useI18n();
|
|
1701
|
+
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"2.0.0-beta.1"}/assets/piano.mp3`, } = props;
|
|
1542
1702
|
// Update audio output device when selection changes
|
|
1543
1703
|
react.useEffect(() => {
|
|
1544
1704
|
const audio = audioElementRef.current;
|
|
@@ -1573,7 +1733,9 @@ const SpeakerTest = (props) => {
|
|
|
1573
1733
|
}
|
|
1574
1734
|
}, [isPlaying, audioUrl]);
|
|
1575
1735
|
const handleAudioEnded = react.useCallback(() => setIsPlaying(false), []);
|
|
1576
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__speaker-test", children: [jsxRuntime.jsx("audio", { ref: audioElementRef, onEnded: handleAudioEnded, onPause: handleAudioEnded }), jsxRuntime.jsx(CompositeButton, { className: "str-video__speaker-test__button", onClick: handleStartTest, type: "button", children: jsxRuntime.jsxs("div", { className: "str-video__speaker-test__button-content", children: [jsxRuntime.jsx(Icon, { icon: "speaker" }), isPlaying
|
|
1736
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__speaker-test", children: [jsxRuntime.jsx("audio", { ref: audioElementRef, onEnded: handleAudioEnded, onPause: handleAudioEnded }), jsxRuntime.jsx(CompositeButton, { className: "str-video__speaker-test__button", appearance: "outline", size: "sm", onClick: handleStartTest, type: "button", children: jsxRuntime.jsxs("div", { className: "str-video__speaker-test__button-content", children: [jsxRuntime.jsx(Icon, { icon: "speaker" }), isPlaying
|
|
1737
|
+
? t('deviceSettings.speakerTest.stopTest.label', 'Stop test')
|
|
1738
|
+
: t('deviceSettings.speakerTest.testSpeaker.label', 'Test speaker')] }) })] }));
|
|
1577
1739
|
};
|
|
1578
1740
|
|
|
1579
1741
|
const DeviceSelectorAudioInput = ({ title, visualType, volumeIndicatorVisible = true, }) => {
|
|
@@ -1581,7 +1743,7 @@ const DeviceSelectorAudioInput = ({ title, visualType, volumeIndicatorVisible =
|
|
|
1581
1743
|
const { microphone, selectedDevice, devices } = useMicrophoneState();
|
|
1582
1744
|
return (jsxRuntime.jsx(DeviceSelector, { devices: devices || [], selectedDeviceId: selectedDevice, type: "audioinput", onChange: async (deviceId) => {
|
|
1583
1745
|
await microphone.select(deviceId);
|
|
1584
|
-
}, title: title, visualType: visualType, icon: "mic", PreviewItem: DeviceAudioPreviewItem, children: volumeIndicatorVisible && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("hr", { className: "str-video__device-settings__separator" })
|
|
1746
|
+
}, title: title, visualType: visualType, icon: "mic", PreviewItem: DeviceAudioPreviewItem, children: volumeIndicatorVisible && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(AudioVolumeIndicator, {}), jsxRuntime.jsx("hr", { className: "str-video__device-settings__separator" })] })) }));
|
|
1585
1747
|
};
|
|
1586
1748
|
const DeviceSelectorAudioOutput = ({ title, visualType, speakerTestVisible = true, speakerTestAudioUrl, }) => {
|
|
1587
1749
|
const { useSpeakerState } = videoReactBindings.useCallStateHooks();
|
|
@@ -1590,7 +1752,7 @@ const DeviceSelectorAudioOutput = ({ title, visualType, speakerTestVisible = tru
|
|
|
1590
1752
|
return null;
|
|
1591
1753
|
return (jsxRuntime.jsx(DeviceSelector, { devices: devices, type: "audiooutput", selectedDeviceId: selectedDevice, onChange: (deviceId) => {
|
|
1592
1754
|
speaker.select(deviceId);
|
|
1593
|
-
}, title: title, visualType: visualType, icon: "speaker", children: speakerTestVisible &&
|
|
1755
|
+
}, title: title, visualType: visualType, icon: "speaker", children: speakerTestVisible && jsxRuntime.jsx(SpeakerTest, { audioUrl: speakerTestAudioUrl }) }));
|
|
1594
1756
|
};
|
|
1595
1757
|
|
|
1596
1758
|
const DeviceVideoPreview = ({ deviceId }) => {
|
|
@@ -1641,38 +1803,41 @@ const DeviceSettings = ({ visualType = exports.MenuVisualType.MENU, }) => {
|
|
|
1641
1803
|
return (jsxRuntime.jsx(MenuToggle, { placement: "bottom-end", ToggleButton: ToggleDeviceSettingsMenuButton, visualType: visualType, children: jsxRuntime.jsx(Menu, {}) }));
|
|
1642
1804
|
};
|
|
1643
1805
|
const Menu = () => {
|
|
1644
|
-
const { t } =
|
|
1645
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__device-settings", children: [jsxRuntime.jsx(DeviceSelectorVideo, { title: t('Select a Camera') }), jsxRuntime.jsx(DeviceSelectorAudioInput, { title: t('Select a Mic') }), jsxRuntime.jsx(DeviceSelectorAudioOutput, { title: t('Select Speakers') })] }));
|
|
1806
|
+
const { t } = useI18n();
|
|
1807
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__device-settings", children: [jsxRuntime.jsx(DeviceSelectorVideo, { title: t('deviceSettings.selectCamera.title', 'Select a Camera') }), jsxRuntime.jsx(DeviceSelectorAudioInput, { title: t('deviceSettings.selectMic.title', 'Select a Mic') }), jsxRuntime.jsx(DeviceSelectorAudioOutput, { title: t('deviceSettings.selectSpeakers.title', 'Select Speakers') })] }));
|
|
1646
1808
|
};
|
|
1647
1809
|
const ToggleDeviceSettingsMenuButton = react.forwardRef(function ToggleDeviceSettingsMenuButtonRender({ menuShown }, ref) {
|
|
1648
|
-
const { t } =
|
|
1649
|
-
return (jsxRuntime.jsx(IconButton, { className: clsx('str-video__device-settings__button', {
|
|
1810
|
+
const { t } = useI18n();
|
|
1811
|
+
return (jsxRuntime.jsx(IconButton, { active: menuShown, size: "sm", variant: "secondary", className: clsx('str-video__device-settings__button', {
|
|
1650
1812
|
'str-video__device-settings__button--active': menuShown,
|
|
1651
|
-
}), title: t('Toggle device menu'), icon: "device-settings", ref: ref }));
|
|
1813
|
+
}), title: t('deviceSettings.toggleDeviceMenu.title', 'Toggle device menu'), icon: "device-settings", ref: ref }));
|
|
1652
1814
|
});
|
|
1653
1815
|
|
|
1654
1816
|
const ToggleAudioPreviewButton = (props) => {
|
|
1655
1817
|
const { caption, Menu = DeviceSelectorAudioInput, menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1656
|
-
const { t } =
|
|
1818
|
+
const { t } = useI18n();
|
|
1657
1819
|
const { useMicrophoneState, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
1658
1820
|
const { microphone, hasBrowserPermission, isPromptingPermission, optionsAwareIsMute, isTogglePending, } = useMicrophoneState({ optimisticUpdates });
|
|
1659
1821
|
const localParticipant = useLocalParticipant();
|
|
1660
1822
|
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(videoClient.SfuModels.TrackType.AUDIO);
|
|
1661
1823
|
const [tooltipDisabled, setTooltipDisabled] = react.useState(false);
|
|
1662
1824
|
const handleClick = createCallControlHandler(props, () => microphone.toggle());
|
|
1663
|
-
return (jsxRuntime.jsx(WithTooltip, { title:
|
|
1664
|
-
? t('
|
|
1665
|
-
:
|
|
1666
|
-
? t('
|
|
1667
|
-
:
|
|
1825
|
+
return (jsxRuntime.jsx(WithTooltip, { title: isPromptingPermission
|
|
1826
|
+
? t('common.waitingForPermission.title', 'Waiting for permission')
|
|
1827
|
+
: !hasBrowserPermission
|
|
1828
|
+
? t('callControls.toggleAudioButton.checkBrowserAudioPermissions.title', 'Check your browser audio permissions')
|
|
1829
|
+
: isSystemMuted
|
|
1830
|
+
? t('callControls.toggleAudioButton.microphonePausedBySystem.title', 'Microphone is paused by your system')
|
|
1831
|
+
: (caption ??
|
|
1832
|
+
t('callControls.toggleAudioButton.mic.title', 'Mic')), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, className: clsx(!hasBrowserPermission && 'str-video__device-unavailable'), variant: optionsAwareIsMute ? 'destructive' : 'secondary', disabled: !hasBrowserPermission || (!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute
|
|
1668
1833
|
? 'preview-audio-unmute-button'
|
|
1669
1834
|
: 'preview-audio-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1670
1835
|
setTooltipDisabled(shown);
|
|
1671
1836
|
onMenuToggle?.(shown);
|
|
1672
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: !optionsAwareIsMute ? 'mic' : 'mic-off' }),
|
|
1837
|
+
}, children: [jsxRuntime.jsx(Icon, { icon: !optionsAwareIsMute ? 'mic' : 'mic-off' }), isPromptingPermission ? (jsxRuntime.jsx(Badge, { variant: "error", icon: "question-mark-fill" })) : !hasBrowserPermission || isSystemMuted ? (jsxRuntime.jsx(Badge, { variant: "error", icon: "exclamation-mark-fill" })) : null] }) }));
|
|
1673
1838
|
};
|
|
1674
1839
|
const ToggleAudioPublishingButton = (props) => {
|
|
1675
|
-
const { t } =
|
|
1840
|
+
const { t } = useI18n();
|
|
1676
1841
|
const { caption, Menu = jsxRuntime.jsx(DeviceSelectorAudioInput, { visualType: "list" }), menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1677
1842
|
const { hasPermission, requestPermission, isAwaitingPermission } = useRequestPermission(videoClient.RequestPermissionRequestPermissionsEnum.SEND_AUDIO);
|
|
1678
1843
|
const { useMicrophoneState, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
@@ -1688,43 +1853,49 @@ const ToggleAudioPublishingButton = (props) => {
|
|
|
1688
1853
|
await microphone.toggle();
|
|
1689
1854
|
}
|
|
1690
1855
|
});
|
|
1691
|
-
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], children: jsxRuntime.jsx(PermissionNotification, { permission: videoClient.OwnCapability.SEND_AUDIO, isAwaitingApproval: isAwaitingPermission, messageApproved: t('You can now speak.'), messageAwaitingApproval: t('Awaiting for an approval to speak.'), messageRevoked: t('You can no longer speak.'), children: jsxRuntime.jsx(WithTooltip, { title:
|
|
1692
|
-
? t('
|
|
1693
|
-
: !
|
|
1694
|
-
? t('
|
|
1695
|
-
:
|
|
1696
|
-
? t('
|
|
1697
|
-
:
|
|
1856
|
+
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], children: jsxRuntime.jsx(PermissionNotification, { permission: videoClient.OwnCapability.SEND_AUDIO, isAwaitingApproval: isAwaitingPermission, messageApproved: t('callControls.toggleAudioButton.permissionGranted.text', 'You can now speak.'), messageAwaitingApproval: t('callControls.toggleAudioButton.awaitingApproval.text', 'Awaiting for an approval to speak.'), messageRevoked: t('callControls.toggleAudioButton.permissionRevoked.text', 'You can no longer speak.'), children: jsxRuntime.jsx(WithTooltip, { title: isPromptingPermission
|
|
1857
|
+
? t('common.waitingForPermission.title', 'Waiting for permission')
|
|
1858
|
+
: !hasPermission
|
|
1859
|
+
? t('callControls.toggleAudioButton.noPermissionToShareAudio.title', 'You have no permission to share your audio')
|
|
1860
|
+
: !hasBrowserPermission
|
|
1861
|
+
? t('callControls.toggleAudioButton.checkBrowserMicPermissions.title', 'Check your browser mic permissions')
|
|
1862
|
+
: isSystemMuted
|
|
1863
|
+
? t('callControls.toggleAudioButton.microphonePausedBySystem.title', 'Microphone is paused by your system')
|
|
1864
|
+
: (caption ??
|
|
1865
|
+
t('callControls.toggleAudioButton.mic.title', 'Mic')), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, variant: optionsAwareIsMute ? 'destructive' : 'secondary', disabled: !hasBrowserPermission ||
|
|
1698
1866
|
!hasPermission ||
|
|
1699
1867
|
// disable button while the toggle action is pending when not using optimistic updates
|
|
1700
1868
|
(!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute ? 'audio-unmute-button' : 'audio-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, menuOffset: 16, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1701
1869
|
setTooltipDisabled(shown);
|
|
1702
1870
|
onMenuToggle?.(shown);
|
|
1703
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: optionsAwareIsMute ? 'mic-off' : 'mic' }),
|
|
1871
|
+
}, children: [jsxRuntime.jsx(Icon, { icon: optionsAwareIsMute ? 'mic-off' : 'mic' }), isPromptingPermission ? (jsxRuntime.jsx(Badge, { variant: "error", icon: "question-mark-fill" })) : !hasBrowserPermission || !hasPermission || isSystemMuted ? (jsxRuntime.jsx(Badge, { variant: "error", icon: "exclamation-mark-fill" })) : null] }) }) }) }));
|
|
1704
1872
|
};
|
|
1705
1873
|
|
|
1706
1874
|
const ToggleVideoPreviewButton = (props) => {
|
|
1707
1875
|
const { caption, Menu = DeviceSelectorVideo, menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1708
|
-
const { t } =
|
|
1876
|
+
const { t } = useI18n();
|
|
1709
1877
|
const { useCameraState, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
1710
1878
|
const { camera, hasBrowserPermission, isPromptingPermission, isTogglePending, optionsAwareIsMute, } = useCameraState({ optimisticUpdates });
|
|
1711
1879
|
const localParticipant = useLocalParticipant();
|
|
1712
1880
|
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(videoClient.SfuModels.TrackType.VIDEO);
|
|
1713
1881
|
const [tooltipDisabled, setTooltipDisabled] = react.useState(false);
|
|
1714
1882
|
const handleClick = createCallControlHandler(props, () => camera.toggle());
|
|
1715
|
-
return (jsxRuntime.jsx(WithTooltip, { title:
|
|
1716
|
-
? t('
|
|
1717
|
-
:
|
|
1718
|
-
? t('
|
|
1719
|
-
:
|
|
1883
|
+
return (jsxRuntime.jsx(WithTooltip, { title: isPromptingPermission
|
|
1884
|
+
? t('common.waitingForPermission.title', 'Waiting for permission')
|
|
1885
|
+
: !hasBrowserPermission
|
|
1886
|
+
? t('callControls.toggleVideoButton.checkBrowserVideoPermissions.title', 'Check your browser video permissions')
|
|
1887
|
+
: isSystemMuted
|
|
1888
|
+
? t('callControls.toggleVideoButton.cameraPausedBySystem.title', 'Camera is paused by your system')
|
|
1889
|
+
: (caption ??
|
|
1890
|
+
t('callControls.toggleVideoButton.video.title', 'Video')), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, className: clsx(!hasBrowserPermission && 'str-video__device-unavailable'), variant: optionsAwareIsMute ? 'destructive' : 'secondary', "data-testid": optionsAwareIsMute
|
|
1720
1891
|
? 'preview-video-unmute-button'
|
|
1721
1892
|
: 'preview-video-mute-button', onClick: handleClick, disabled: !hasBrowserPermission || (!optimisticUpdates && isTogglePending), Menu: Menu, menuPlacement: menuPlacement, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1722
1893
|
setTooltipDisabled(shown);
|
|
1723
1894
|
onMenuToggle?.(shown);
|
|
1724
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: !optionsAwareIsMute ? 'camera' : 'camera-off' }),
|
|
1895
|
+
}, children: [jsxRuntime.jsx(Icon, { icon: !optionsAwareIsMute ? 'camera' : 'camera-off' }), isPromptingPermission ? (jsxRuntime.jsx(Badge, { variant: "error", icon: "question-mark-fill" })) : !hasBrowserPermission || isSystemMuted ? (jsxRuntime.jsx(Badge, { variant: "error", icon: "exclamation-mark-fill" })) : null] }) }));
|
|
1725
1896
|
};
|
|
1726
1897
|
const ToggleVideoPublishingButton = (props) => {
|
|
1727
|
-
const { t } =
|
|
1898
|
+
const { t } = useI18n();
|
|
1728
1899
|
const { caption, Menu = jsxRuntime.jsx(DeviceSelectorVideo, { visualType: "list" }), menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1729
1900
|
const { hasPermission, requestPermission, isAwaitingPermission } = useRequestPermission(videoClient.RequestPermissionRequestPermissionsEnum.SEND_VIDEO);
|
|
1730
1901
|
const { useCameraState, useCallSettings, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
@@ -1742,36 +1913,37 @@ const ToggleVideoPublishingButton = (props) => {
|
|
|
1742
1913
|
await camera.toggle();
|
|
1743
1914
|
}
|
|
1744
1915
|
});
|
|
1745
|
-
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_VIDEO], children: jsxRuntime.jsx(PermissionNotification, { permission: videoClient.OwnCapability.SEND_VIDEO, isAwaitingApproval: isAwaitingPermission, messageApproved: t('You can now share your video.'), messageAwaitingApproval: t('Awaiting for an approval to share your video.'), messageRevoked: t('You can no longer share your video.'), children: jsxRuntime.jsx(WithTooltip, { title:
|
|
1746
|
-
? t('
|
|
1747
|
-
: !
|
|
1748
|
-
? t('
|
|
1749
|
-
: !
|
|
1750
|
-
? t('
|
|
1751
|
-
:
|
|
1752
|
-
? t('
|
|
1753
|
-
:
|
|
1916
|
+
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_VIDEO], children: jsxRuntime.jsx(PermissionNotification, { permission: videoClient.OwnCapability.SEND_VIDEO, isAwaitingApproval: isAwaitingPermission, messageApproved: t('callControls.toggleVideoButton.permissionGranted.text', 'You can now share your video.'), messageAwaitingApproval: t('callControls.toggleVideoButton.awaitingApproval.text', 'Awaiting for an approval to share your video.'), messageRevoked: t('callControls.toggleVideoButton.permissionRevoked.text', 'You can no longer share your video.'), children: jsxRuntime.jsx(WithTooltip, { title: isPromptingPermission
|
|
1917
|
+
? t('common.waitingForPermission.title', 'Waiting for permission')
|
|
1918
|
+
: !hasPermission
|
|
1919
|
+
? t('callControls.toggleVideoButton.noPermissionToShareVideo.title', 'You have no permission to share your video')
|
|
1920
|
+
: !hasBrowserPermission
|
|
1921
|
+
? t('callControls.toggleVideoButton.checkBrowserVideoPermissions.title', 'Check your browser video permissions')
|
|
1922
|
+
: !isPublishingVideoAllowed
|
|
1923
|
+
? t('callControls.toggleVideoButton.videoPublishingDisabled.title', 'Video publishing is disabled by the system')
|
|
1924
|
+
: isSystemMuted
|
|
1925
|
+
? t('callControls.toggleVideoButton.cameraPausedBySystem.title', 'Camera is paused by your system')
|
|
1926
|
+
: caption ||
|
|
1927
|
+
t('callControls.toggleVideoButton.video.title', 'Video'), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, variant: optionsAwareIsMute ? 'destructive' : 'secondary', disabled: !hasBrowserPermission ||
|
|
1754
1928
|
!hasPermission ||
|
|
1755
1929
|
!isPublishingVideoAllowed ||
|
|
1756
1930
|
(!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute ? 'video-unmute-button' : 'video-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, menuOffset: 16, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1757
1931
|
setTooltipDisabled(shown);
|
|
1758
1932
|
onMenuToggle?.(shown);
|
|
1759
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: optionsAwareIsMute ? 'camera-off' : 'camera' }), (!hasBrowserPermission ||
|
|
1933
|
+
}, children: [jsxRuntime.jsx(Icon, { icon: optionsAwareIsMute ? 'camera-off' : 'camera' }), isPromptingPermission ? (jsxRuntime.jsx(Badge, { variant: "error", icon: "question-mark-fill" })) : !hasBrowserPermission ||
|
|
1760
1934
|
!hasPermission ||
|
|
1761
|
-
!isPublishingVideoAllowed
|
|
1762
|
-
|
|
1763
|
-
hasPermission &&
|
|
1764
|
-
isPublishingVideoAllowed && (jsxRuntime.jsx("span", { className: "str-video__system-muted", title: t('Camera is paused by your system'), children: "!" }))] }) }) }) }));
|
|
1935
|
+
!isPublishingVideoAllowed ||
|
|
1936
|
+
isSystemMuted ? (jsxRuntime.jsx(Badge, { variant: "error", icon: "exclamation-mark-fill" })) : null] }) }) }) }));
|
|
1765
1937
|
};
|
|
1766
1938
|
|
|
1767
1939
|
const EndCallMenu = (props) => {
|
|
1768
1940
|
const { onLeave, onEnd } = props;
|
|
1769
|
-
const { t } =
|
|
1770
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__end-call__confirmation", children: [jsxRuntime.jsxs("
|
|
1941
|
+
const { t } = useI18n();
|
|
1942
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__end-call__confirmation", children: [jsxRuntime.jsxs(Button, { variant: "secondary", appearance: "outline", className: "str-video__end-call__leave", "data-testid": "leave-call-button", onClick: onLeave, children: [jsxRuntime.jsx(Icon, { icon: "logout" }), t('callControls.cancelCallButton.leaveCall.title', 'Leave call')] }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.END_CALL], children: jsxRuntime.jsxs(Button, { variant: "destructive", className: "str-video__end-call__end", "data-testid": "end-call-for-all-button", onClick: onEnd, children: [jsxRuntime.jsx(Icon, { icon: "call-end" }), t('callControls.cancelCallButton.endCallForAll.label', 'End call for all')] }) })] }));
|
|
1771
1943
|
};
|
|
1772
1944
|
const CancelCallToggleMenuButton = react.forwardRef(function CancelCallToggleMenuButtonRender({ menuShown }, ref) {
|
|
1773
|
-
const { t } =
|
|
1774
|
-
return (jsxRuntime.jsx(WithTooltip, { title: t('Leave call'), tooltipDisabled: menuShown, children: jsxRuntime.jsx(IconButton, { icon: menuShown ? 'close' : 'call-end', variant:
|
|
1945
|
+
const { t } = useI18n();
|
|
1946
|
+
return (jsxRuntime.jsx(WithTooltip, { title: t('callControls.cancelCallButton.leaveCall.title', 'Leave call'), tooltipDisabled: menuShown, children: jsxRuntime.jsx(IconButton, { icon: menuShown ? 'close' : 'call-end', variant: "destructive", "data-testid": "leave-call-button", ref: ref }) }));
|
|
1775
1947
|
});
|
|
1776
1948
|
const CancelCallConfirmButton = ({ onClick, onLeave, }) => {
|
|
1777
1949
|
const call = videoReactBindings.useCall();
|
|
@@ -1807,9 +1979,9 @@ const CancelCallConfirmButton = ({ onClick, onLeave, }) => {
|
|
|
1807
1979
|
}, [onClick, onLeave, call]);
|
|
1808
1980
|
return (jsxRuntime.jsx(MenuToggle, { placement: "top-start", ToggleButton: CancelCallToggleMenuButton, children: jsxRuntime.jsx(EndCallMenu, { onEnd: handleEndCall, onLeave: handleLeave }) }));
|
|
1809
1981
|
};
|
|
1810
|
-
const CancelCallButton = ({ disabled, caption, onClick, onLeave, }) => {
|
|
1982
|
+
const CancelCallButton = ({ disabled, caption, size, onClick, onLeave, }) => {
|
|
1811
1983
|
const call = videoReactBindings.useCall();
|
|
1812
|
-
const { t } =
|
|
1984
|
+
const { t } = useI18n();
|
|
1813
1985
|
const handleClick = react.useCallback(async (e) => {
|
|
1814
1986
|
if (onClick) {
|
|
1815
1987
|
onClick(e);
|
|
@@ -1825,7 +1997,8 @@ const CancelCallButton = ({ disabled, caption, onClick, onLeave, }) => {
|
|
|
1825
1997
|
}
|
|
1826
1998
|
}
|
|
1827
1999
|
}, [onClick, onLeave, call]);
|
|
1828
|
-
return (jsxRuntime.jsx(IconButton, { disabled: disabled, icon: "call-end", variant: "
|
|
2000
|
+
return (jsxRuntime.jsx(IconButton, { size: size, disabled: disabled, icon: "call-end", variant: "destructive", title: caption ??
|
|
2001
|
+
t('callControls.cancelCallButton.leaveCall.title', 'Leave call'), "data-testid": "cancel-call-button", onClick: handleClick }));
|
|
1829
2002
|
};
|
|
1830
2003
|
|
|
1831
2004
|
const CallControls = ({ onLeave }) => (jsxRuntime.jsxs("div", { className: "str-video__call-controls", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], children: jsxRuntime.jsx(SpeakingWhileMutedNotification, { children: jsxRuntime.jsx(ToggleAudioPublishingButton, {}) }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_VIDEO], children: jsxRuntime.jsx(ToggleVideoPublishingButton, {}) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx(ReactionsButton, {}) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SCREENSHARE], children: jsxRuntime.jsx(ScreenShareButton, {}) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [
|
|
@@ -1833,188 +2006,12 @@ const CallControls = ({ onLeave }) => (jsxRuntime.jsxs("div", { className: "str-
|
|
|
1833
2006
|
videoClient.OwnCapability.STOP_RECORD_CALL,
|
|
1834
2007
|
], children: jsxRuntime.jsx(RecordCallButton, {}) }), jsxRuntime.jsx(CancelCallButton, { onLeave: onLeave })] }));
|
|
1835
2008
|
|
|
1836
|
-
const CallStatsLatencyChart = react.lazy(() => Promise.resolve().then(function () { return require('./latency-chart-CpL1M_s0.cjs.js'); }));
|
|
1837
|
-
var Status;
|
|
1838
|
-
(function (Status) {
|
|
1839
|
-
Status["GOOD"] = "Good";
|
|
1840
|
-
Status["OK"] = "Ok";
|
|
1841
|
-
Status["BAD"] = "Bad";
|
|
1842
|
-
})(Status || (Status = {}));
|
|
1843
|
-
const CallStats = (props) => {
|
|
1844
|
-
const { latencyLowBound = 75, latencyHighBound = 400, audioJitterLowBound = 10, audioJitterHighBound = 30, videoJitterLowBound = 20, videoJitterHighBound = 50, showCodecInfo = false, LatencyChartSuspenseFallback = null, } = props;
|
|
1845
|
-
const [latencyBuffer, setLatencyBuffer] = react.useState(() => {
|
|
1846
|
-
const now = Date.now();
|
|
1847
|
-
return Array.from({ length: 20 }, (_, i) => ({ x: now + i, y: 0 }));
|
|
1848
|
-
});
|
|
1849
|
-
const { t } = videoReactBindings.useI18n();
|
|
1850
|
-
const [publishBitrate, setPublishBitrate] = react.useState('-');
|
|
1851
|
-
const [subscribeBitrate, setSubscribeBitrate] = react.useState('-');
|
|
1852
|
-
const [publishAudioBitrate, setPublishAudioBitrate] = react.useState('-');
|
|
1853
|
-
const [subscribeAudioBitrate, setSubscribeAudioBitrate] = react.useState('-');
|
|
1854
|
-
const previousStats = react.useRef(undefined);
|
|
1855
|
-
const { useCallStatsReport } = videoReactBindings.useCallStateHooks();
|
|
1856
|
-
const callStatsReport = useCallStatsReport();
|
|
1857
|
-
react.useEffect(() => {
|
|
1858
|
-
if (!callStatsReport)
|
|
1859
|
-
return;
|
|
1860
|
-
if (!previousStats.current) {
|
|
1861
|
-
previousStats.current = callStatsReport;
|
|
1862
|
-
return;
|
|
1863
|
-
}
|
|
1864
|
-
const previousCallStatsReport = previousStats.current;
|
|
1865
|
-
setPublishBitrate(() => {
|
|
1866
|
-
return calculatePublishBitrate(previousCallStatsReport, callStatsReport);
|
|
1867
|
-
});
|
|
1868
|
-
setSubscribeBitrate(() => {
|
|
1869
|
-
return calculateSubscribeBitrate(previousCallStatsReport, callStatsReport);
|
|
1870
|
-
});
|
|
1871
|
-
setPublishAudioBitrate(() => {
|
|
1872
|
-
return calculatePublishAudioBitrate(previousCallStatsReport, callStatsReport);
|
|
1873
|
-
});
|
|
1874
|
-
setSubscribeAudioBitrate(() => {
|
|
1875
|
-
return calculateSubscribeAudioBitrate(previousCallStatsReport, callStatsReport);
|
|
1876
|
-
});
|
|
1877
|
-
setLatencyBuffer((latencyBuf) => {
|
|
1878
|
-
const newLatencyBuffer = latencyBuf.slice(-19);
|
|
1879
|
-
newLatencyBuffer.push({
|
|
1880
|
-
x: callStatsReport.timestamp,
|
|
1881
|
-
y: callStatsReport.publisherStats.averageRoundTripTimeInMs ||
|
|
1882
|
-
callStatsReport.publisherAudioStats.averageRoundTripTimeInMs,
|
|
1883
|
-
});
|
|
1884
|
-
return newLatencyBuffer;
|
|
1885
|
-
});
|
|
1886
|
-
previousStats.current = callStatsReport;
|
|
1887
|
-
}, [callStatsReport]);
|
|
1888
|
-
const latencyComparison = {
|
|
1889
|
-
lowBound: latencyLowBound,
|
|
1890
|
-
highBound: latencyHighBound,
|
|
1891
|
-
value: callStatsReport?.publisherStats.averageRoundTripTimeInMs || 0,
|
|
1892
|
-
};
|
|
1893
|
-
const audioJitterComparison = {
|
|
1894
|
-
lowBound: audioJitterLowBound,
|
|
1895
|
-
highBound: audioJitterHighBound,
|
|
1896
|
-
};
|
|
1897
|
-
const videoJitterComparison = {
|
|
1898
|
-
lowBound: videoJitterLowBound,
|
|
1899
|
-
highBound: videoJitterHighBound,
|
|
1900
|
-
};
|
|
1901
|
-
return (jsxRuntime.jsx("div", { className: "str-video__call-stats", children: callStatsReport && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "str-video__call-stats__header", children: [jsxRuntime.jsxs("h3", { className: "str-video__call-stats__heading", children: [jsxRuntime.jsx(Icon, { className: "str-video__call-stats__icon", icon: "call-latency" }), t('Call Latency')] }), jsxRuntime.jsx("p", { className: "str-video__call-stats__description", children: t('Very high latency values may reduce call quality, cause lag, and make the call less enjoyable.') })] }), jsxRuntime.jsx("div", { className: "str-video__call-stats__latencychart", children: jsxRuntime.jsx(react.Suspense, { fallback: LatencyChartSuspenseFallback, children: jsxRuntime.jsx(CallStatsLatencyChart, { values: latencyBuffer }) }) }), jsxRuntime.jsxs("div", { className: "str-video__call-stats__header", children: [jsxRuntime.jsxs("h3", { className: "str-video__call-stats__heading", children: [jsxRuntime.jsx(Icon, { className: "str-video__call-stats__icon", icon: "network-quality" }), t('Video performance')] }), jsxRuntime.jsx("p", { className: "str-video__call-stats__description", children: t('Review the key data points below to assess call performance') })] }), jsxRuntime.jsxs("div", { className: "str-video__call-stats__card-container", children: [jsxRuntime.jsx(StatCard, { label: t('Region'), value: callStatsReport.datacenter }), jsxRuntime.jsx(StatCard, { label: t('Latency'), value: `${callStatsReport.publisherStats.averageRoundTripTimeInMs} ms.`, comparison: latencyComparison }), jsxRuntime.jsx(StatCard, { label: t('Receive jitter'), value: `${callStatsReport.subscriberStats.averageJitterInMs} ms.`, comparison: {
|
|
1902
|
-
...videoJitterComparison,
|
|
1903
|
-
value: callStatsReport.subscriberStats.averageJitterInMs,
|
|
1904
|
-
} }), jsxRuntime.jsx(StatCard, { label: t('Publish jitter'), value: `${callStatsReport.publisherStats.averageJitterInMs} ms.`, comparison: {
|
|
1905
|
-
...videoJitterComparison,
|
|
1906
|
-
value: callStatsReport.publisherStats.averageJitterInMs,
|
|
1907
|
-
} }), jsxRuntime.jsx(StatCard, { label: `${t('Publish resolution')}${showCodecInfo ? formatCodec(callStatsReport) : ''}`, value: toFrameSize(callStatsReport.publisherStats) }), jsxRuntime.jsx(StatCard, { label: t('Publish quality drop reason'), value: callStatsReport.publisherStats.qualityLimitationReasons }), jsxRuntime.jsx(StatCard, { label: t('Receiving resolution'), value: toFrameSize(callStatsReport.subscriberStats) }), jsxRuntime.jsx(StatCard, { label: t('Receive quality drop reason'), value: callStatsReport.subscriberStats.qualityLimitationReasons }), jsxRuntime.jsx(StatCard, { label: t('Publish bitrate'), value: publishBitrate }), jsxRuntime.jsx(StatCard, { label: t('Receiving bitrate'), value: subscribeBitrate })] }), jsxRuntime.jsxs("div", { className: "str-video__call-stats__header", children: [jsxRuntime.jsxs("h3", { className: "str-video__call-stats__heading", children: [jsxRuntime.jsx(Icon, { className: "str-video__call-stats__icon", icon: "mic" }), t('Audio Performance')] }), jsxRuntime.jsx("p", { className: "str-video__call-stats__description", children: t('Review the key audio data points below to assess audio performance') })] }), jsxRuntime.jsxs("div", { className: "str-video__call-stats__card-container", children: [jsxRuntime.jsx(StatCard, { label: t('Latency'), value: `${callStatsReport.publisherAudioStats.averageRoundTripTimeInMs} ms.`, comparison: latencyComparison }), jsxRuntime.jsx(StatCard, { label: t('Audio codec'), value: formatAudioCodec(callStatsReport) }), jsxRuntime.jsx(StatCard, { label: t('Audio bitrate (publish)'), value: publishAudioBitrate }), jsxRuntime.jsx(StatCard, { label: t('Audio bitrate (receive)'), value: subscribeAudioBitrate }), jsxRuntime.jsx(StatCard, { label: t('Audio jitter (publish)'), value: `${callStatsReport.publisherAudioStats.averageJitterInMs} ms.`, comparison: {
|
|
1908
|
-
...audioJitterComparison,
|
|
1909
|
-
value: callStatsReport.publisherAudioStats.averageJitterInMs,
|
|
1910
|
-
} }), jsxRuntime.jsx(StatCard, { label: t('Audio jitter (receive)'), value: `${callStatsReport.subscriberAudioStats.averageJitterInMs} ms.`, comparison: {
|
|
1911
|
-
...audioJitterComparison,
|
|
1912
|
-
value: callStatsReport.subscriberAudioStats.averageJitterInMs,
|
|
1913
|
-
} })] })] })) }));
|
|
1914
|
-
};
|
|
1915
|
-
const StatCardExplanation = (props) => {
|
|
1916
|
-
const { description } = props;
|
|
1917
|
-
const [isOpen, setIsOpen] = react.useState(false);
|
|
1918
|
-
const { refs, floatingStyles, context } = react$1.useFloating({
|
|
1919
|
-
open: isOpen,
|
|
1920
|
-
onOpenChange: setIsOpen,
|
|
1921
|
-
});
|
|
1922
|
-
const hover = react$1.useHover(context);
|
|
1923
|
-
const { getReferenceProps, getFloatingProps } = react$1.useInteractions([hover]);
|
|
1924
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "str-video__call-explanation", ref: refs.setReference, ...getReferenceProps(), children: jsxRuntime.jsx(Icon, { className: "str-video__call-explanation__icon", icon: "info" }) }), isOpen && (jsxRuntime.jsx("div", { className: "str-video__call-explanation__description", ref: refs.setFloating, style: floatingStyles, ...getFloatingProps(), children: description }))] }));
|
|
1925
|
-
};
|
|
1926
|
-
const StatsTag = (props) => {
|
|
1927
|
-
const { children, status } = props;
|
|
1928
|
-
return (jsxRuntime.jsx("div", { className: clsx('str-video__call-stats__tag', {
|
|
1929
|
-
'str-video__call-stats__tag--good': status === Status.GOOD,
|
|
1930
|
-
'str-video__call-stats__tag--ok': status === Status.OK,
|
|
1931
|
-
'str-video__call-stats__tag--bad': status === Status.BAD,
|
|
1932
|
-
}), children: jsxRuntime.jsx("div", { className: "str-video__call-stats__tag__text", children: children }) }));
|
|
1933
|
-
};
|
|
1934
|
-
const StatCard = (props) => {
|
|
1935
|
-
const { label, value, description, comparison } = props;
|
|
1936
|
-
const { t } = videoReactBindings.useI18n();
|
|
1937
|
-
const status = comparison ? toStatus(comparison) : undefined;
|
|
1938
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__call-stats__card", children: [jsxRuntime.jsxs("div", { className: "str-video__call-stats__card-content", children: [jsxRuntime.jsxs("div", { className: "str-video__call-stats__card-label", children: [label, description && jsxRuntime.jsx(StatCardExplanation, { description: description })] }), jsxRuntime.jsx("div", { className: "str-video__call-stats__card-value", children: value })] }), status && jsxRuntime.jsx(StatsTag, { status: status, children: t(status) })] }));
|
|
1939
|
-
};
|
|
1940
|
-
const toStatus = (config) => {
|
|
1941
|
-
const { value, lowBound, highBound } = config;
|
|
1942
|
-
if (value <= lowBound)
|
|
1943
|
-
return Status.GOOD;
|
|
1944
|
-
if (value >= lowBound && value <= highBound)
|
|
1945
|
-
return Status.OK;
|
|
1946
|
-
if (value >= highBound)
|
|
1947
|
-
return Status.BAD;
|
|
1948
|
-
return Status.GOOD;
|
|
1949
|
-
};
|
|
1950
|
-
const toFrameSize = (stats) => {
|
|
1951
|
-
const { highestFrameWidth: w, highestFrameHeight: h, highestFramesPerSecond: fps, } = stats;
|
|
1952
|
-
let size = `-`;
|
|
1953
|
-
if (w && h) {
|
|
1954
|
-
size = `${w}x${h}`;
|
|
1955
|
-
if (fps) {
|
|
1956
|
-
size += `@${fps}fps.`;
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
return size;
|
|
1960
|
-
};
|
|
1961
|
-
const formatCodec = (callStatsReport) => {
|
|
1962
|
-
const { codecPerTrackType } = callStatsReport.publisherStats;
|
|
1963
|
-
if (!codecPerTrackType || !codecPerTrackType[videoClient.SfuModels.TrackType.VIDEO]) {
|
|
1964
|
-
return '';
|
|
1965
|
-
}
|
|
1966
|
-
const [, name] = codecPerTrackType[videoClient.SfuModels.TrackType.VIDEO].split('/');
|
|
1967
|
-
return name ? ` (${name})` : '';
|
|
1968
|
-
};
|
|
1969
|
-
const formatAudioCodec = (callStatsReport) => {
|
|
1970
|
-
const { codecPerTrackType } = callStatsReport.publisherAudioStats;
|
|
1971
|
-
if (!codecPerTrackType || !codecPerTrackType[videoClient.SfuModels.TrackType.AUDIO]) {
|
|
1972
|
-
return '';
|
|
1973
|
-
}
|
|
1974
|
-
const [, name] = codecPerTrackType[videoClient.SfuModels.TrackType.AUDIO].split('/');
|
|
1975
|
-
return name ?? '';
|
|
1976
|
-
};
|
|
1977
|
-
const calculatePublishBitrate = (previousCallStatsReport, callStatsReport) => {
|
|
1978
|
-
const { publisherStats: { totalBytesSent: previousTotalBytesSent, timestamp: previousTimestamp, }, } = previousCallStatsReport;
|
|
1979
|
-
const { publisherStats: { totalBytesSent, timestamp }, } = callStatsReport;
|
|
1980
|
-
const bytesSent = totalBytesSent - previousTotalBytesSent;
|
|
1981
|
-
const timeElapsed = timestamp - previousTimestamp;
|
|
1982
|
-
return `${((bytesSent * 8) / timeElapsed).toFixed(2)} kbps`;
|
|
1983
|
-
};
|
|
1984
|
-
const calculateSubscribeBitrate = (previousCallStatsReport, callStatsReport) => {
|
|
1985
|
-
const { subscriberStats: { totalBytesReceived: previousTotalBytesReceived, timestamp: previousTimestamp, }, } = previousCallStatsReport;
|
|
1986
|
-
const { subscriberStats: { totalBytesReceived, timestamp }, } = callStatsReport;
|
|
1987
|
-
const bytesReceived = totalBytesReceived - previousTotalBytesReceived;
|
|
1988
|
-
const timeElapsed = timestamp - previousTimestamp;
|
|
1989
|
-
return `${((bytesReceived * 8) / timeElapsed).toFixed(2)} kbps`;
|
|
1990
|
-
};
|
|
1991
|
-
const calculatePublishAudioBitrate = (previousCallStatsReport, callStatsReport) => {
|
|
1992
|
-
const previousAudioStats = previousCallStatsReport.publisherAudioStats;
|
|
1993
|
-
const audioStats = callStatsReport.publisherAudioStats;
|
|
1994
|
-
const bytesSent = audioStats.totalBytesSent - previousAudioStats.totalBytesSent;
|
|
1995
|
-
const timeElapsed = audioStats.timestamp - previousAudioStats.timestamp;
|
|
1996
|
-
return `${((bytesSent * 8) / timeElapsed).toFixed(2)} kbps`;
|
|
1997
|
-
};
|
|
1998
|
-
const calculateSubscribeAudioBitrate = (previousCallStatsReport, callStatsReport) => {
|
|
1999
|
-
const previousAudioStats = previousCallStatsReport.subscriberAudioStats;
|
|
2000
|
-
const audioStats = callStatsReport.subscriberAudioStats;
|
|
2001
|
-
const bytesReceived = audioStats.totalBytesReceived - previousAudioStats.totalBytesReceived;
|
|
2002
|
-
const timeElapsed = audioStats.timestamp - previousAudioStats.timestamp;
|
|
2003
|
-
return `${((bytesReceived * 8) / timeElapsed).toFixed(2)} kbps`;
|
|
2004
|
-
};
|
|
2005
|
-
|
|
2006
|
-
const CallStatsButton = () => (jsxRuntime.jsx(MenuToggle, { placement: "top-end", ToggleButton: ToggleMenuButton, children: jsxRuntime.jsx(CallStats, {}) }));
|
|
2007
|
-
const ToggleMenuButton = react.forwardRef(function ToggleMenuButtonRender(props, ref) {
|
|
2008
|
-
const { t } = videoReactBindings.useI18n();
|
|
2009
|
-
const { caption, menuShown } = props;
|
|
2010
|
-
return (jsxRuntime.jsx(CompositeButton, { ref: ref, active: menuShown, caption: caption, title: caption || t('Statistics'), "data-testid": "stats-button", children: jsxRuntime.jsx(Icon, { icon: "stats" }) }));
|
|
2011
|
-
});
|
|
2012
|
-
|
|
2013
2009
|
const ToggleAudioOutputButton = (props) => {
|
|
2014
|
-
const { t } =
|
|
2010
|
+
const { t } = useI18n();
|
|
2015
2011
|
const { caption, Menu = DeviceSelectorAudioOutput, menuPlacement = 'top', onMenuToggle, } = props;
|
|
2016
2012
|
const [tooltipDisabled, setTooltipDisabled] = react.useState(false);
|
|
2017
|
-
return (jsxRuntime.jsx(WithTooltip, { title: caption ||
|
|
2013
|
+
return (jsxRuntime.jsx(WithTooltip, { title: caption ||
|
|
2014
|
+
t('callControls.toggleAudioOutputButton.speakers.title', 'Speakers'), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsx(CompositeButton, { Menu: Menu, menuPlacement: menuPlacement, caption: caption, "data-testid": "audio-output-button", onMenuToggle: (shown) => {
|
|
2018
2015
|
setTooltipDisabled(shown);
|
|
2019
2016
|
onMenuToggle?.(shown);
|
|
2020
2017
|
}, children: jsxRuntime.jsx(Icon, { icon: "speaker" }) }) }));
|
|
@@ -2031,34 +2028,43 @@ const BlockedUserListingItem = ({ userId }) => {
|
|
|
2031
2028
|
if (userId)
|
|
2032
2029
|
call?.unblockUser(userId);
|
|
2033
2030
|
};
|
|
2034
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__participant-listing-item", children: [jsxRuntime.jsx("div", { className: "str-video__participant-listing-item__display-name", children: userId }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.BLOCK_USERS], children: jsxRuntime.jsx(
|
|
2031
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__participant-listing-item", children: [jsxRuntime.jsx("div", { className: "str-video__participant-listing-item__display-name", children: userId }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.BLOCK_USERS], children: jsxRuntime.jsx(Button, { appearance: "ghost", size: "xs", variant: "secondary", onClick: unblockUserClickHandler, children: "Unblock" }) })] }));
|
|
2035
2032
|
};
|
|
2036
2033
|
|
|
2037
2034
|
const CallParticipantListHeader = ({ onClose, }) => {
|
|
2038
2035
|
const { useParticipants, useAnonymousParticipantCount } = videoReactBindings.useCallStateHooks();
|
|
2039
2036
|
const participants = useParticipants();
|
|
2040
2037
|
const anonymousParticipantCount = useAnonymousParticipantCount();
|
|
2041
|
-
const { t } =
|
|
2042
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__participant-list-header", children: [jsxRuntime.jsxs("div", { className: "str-video__participant-list-header__title", children: [t('Participants'), ' ', jsxRuntime.jsxs("span", { className: "str-video__participant-list-header__title-count", children: ["[", participants.length, "]"] }), anonymousParticipantCount > 0 && (jsxRuntime.jsx("span", { className: "str-video__participant-list-header__title-anonymous", children: t('
|
|
2038
|
+
const { t } = useI18n();
|
|
2039
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__participant-list-header", children: [jsxRuntime.jsxs("div", { className: "str-video__participant-list-header__title", children: [t('common.participants.label', 'Participants'), ' ', jsxRuntime.jsxs("span", { className: "str-video__participant-list-header__title-count", children: ["[", participants.length, "]"] }), anonymousParticipantCount > 0 && (jsxRuntime.jsx("span", { className: "str-video__participant-list-header__title-anonymous", children: t('participantList.anonymousCount.text', ', and ({{ anonymousCount }}) anonymous', { anonymousCount: anonymousParticipantCount }) }))] }), jsxRuntime.jsx(IconButton, { size: "sm", variant: "secondary", onClick: onClose, className: "str-video__participant-list-header__close-button", icon: "close" })] }));
|
|
2043
2040
|
};
|
|
2044
2041
|
|
|
2045
2042
|
const CallParticipantListingItem = react.memo(function CallParticipantListingItemRender({ participant, DisplayName = DefaultDisplayName, }) {
|
|
2046
2043
|
const isAudioOn = videoClient.hasAudio(participant);
|
|
2047
2044
|
const isVideoOn = videoClient.hasVideo(participant);
|
|
2048
2045
|
const isPinnedOn = videoClient.isPinned(participant);
|
|
2049
|
-
const { t } =
|
|
2050
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__participant-listing-item", children: [jsxRuntime.jsx(Avatar, { name: participant.name, imageSrc: participant.image }), jsxRuntime.jsx(DisplayName, { participant: participant }), jsxRuntime.jsxs("div", { className: "str-video__participant-listing-item__media-indicator-group", children: [jsxRuntime.jsx(MediaIndicator, { title: isAudioOn
|
|
2046
|
+
const { t } = useI18n();
|
|
2047
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__participant-listing-item", children: [jsxRuntime.jsx(Avatar, { name: participant.name, imageSrc: participant.image }), jsxRuntime.jsx(DisplayName, { participant: participant }), jsxRuntime.jsxs("div", { className: "str-video__participant-listing-item__media-indicator-group", children: [jsxRuntime.jsx(MediaIndicator, { title: isAudioOn
|
|
2048
|
+
? t('participantList.microphoneOn.title', 'Microphone on')
|
|
2049
|
+
: t('participantList.microphoneOff.title', 'Microphone off'), className: clsx('str-video__participant-listing-item__icon', `str-video__participant-listing-item__icon-${isAudioOn ? 'mic' : 'mic-off'}`) }), jsxRuntime.jsx(MediaIndicator, { title: isVideoOn
|
|
2050
|
+
? t('participantList.cameraOn.title', 'Camera on')
|
|
2051
|
+
: t('participantList.cameraOff.title', 'Camera off'), className: clsx('str-video__participant-listing-item__icon', `str-video__participant-listing-item__icon-${isVideoOn ? 'camera' : 'camera-off'}`) }), isPinnedOn && (jsxRuntime.jsx(MediaIndicator, { title: t('participantList.pinned.title', 'Pinned'), className: clsx('str-video__participant-listing-item__icon', 'str-video__participant-listing-item__icon-pinned') })), jsxRuntime.jsx(MenuToggle, { placement: "bottom-end", ToggleButton: ToggleButton$2, children: jsxRuntime.jsx(ParticipantViewContext.Provider, { value: { participant, trackType: 'none' }, children: jsxRuntime.jsx(ParticipantActionsContextMenu, {}) }) })] })] }));
|
|
2051
2052
|
});
|
|
2052
2053
|
CallParticipantListingItem.displayName = 'CallParticipantListingItem';
|
|
2053
2054
|
const MediaIndicator = (props) => (jsxRuntime.jsx(WithTooltip, { ...props }));
|
|
2054
2055
|
const DefaultDisplayName = ({ participant }) => {
|
|
2055
2056
|
const connectedUser = videoReactBindings.useConnectedUser();
|
|
2056
|
-
const { t } =
|
|
2057
|
-
const meFlag = participant.userId === connectedUser?.id
|
|
2058
|
-
|
|
2057
|
+
const { t } = useI18n();
|
|
2058
|
+
const meFlag = participant.userId === connectedUser?.id
|
|
2059
|
+
? t('participantList.me.text', 'Me')
|
|
2060
|
+
: '';
|
|
2061
|
+
const nameOrId = participant.name ||
|
|
2062
|
+
participant.userId ||
|
|
2063
|
+
t('participantList.unknown.text', 'Unknown');
|
|
2059
2064
|
let displayName;
|
|
2060
2065
|
if (!participant.name) {
|
|
2061
|
-
displayName =
|
|
2066
|
+
displayName =
|
|
2067
|
+
meFlag || nameOrId || t('participantList.unknown.text', 'Unknown');
|
|
2062
2068
|
}
|
|
2063
2069
|
else if (meFlag) {
|
|
2064
2070
|
displayName = `${nameOrId} (${meFlag})`;
|
|
@@ -2069,14 +2075,14 @@ const DefaultDisplayName = ({ participant }) => {
|
|
|
2069
2075
|
return (jsxRuntime.jsx(WithTooltip, { className: "str-video__participant-listing-item__display-name", title: displayName, children: displayName }));
|
|
2070
2076
|
};
|
|
2071
2077
|
const ToggleButton$2 = react.forwardRef(function ToggleButtonRender(props, ref) {
|
|
2072
|
-
return jsxRuntime.jsx(IconButton, {
|
|
2078
|
+
return (jsxRuntime.jsx(IconButton, { className: "str-video__participant-listing-item__menu-button", active: props.menuShown, size: "sm", variant: "secondary", ref: ref, icon: "ellipsis" }));
|
|
2073
2079
|
});
|
|
2074
2080
|
|
|
2075
2081
|
const CallParticipantListing = ({ data, }) => (jsxRuntime.jsx("div", { className: "str-video__participant-listing", children: data.map((participant) => (jsxRuntime.jsx(CallParticipantListingItem, { participant: participant }, participant.sessionId))) }));
|
|
2076
2082
|
|
|
2077
2083
|
const EmptyParticipantSearchList = () => {
|
|
2078
|
-
const { t } =
|
|
2079
|
-
return (jsxRuntime.jsx("div", { className: "str-video__participant-list--empty", children: t('No participants found') }));
|
|
2084
|
+
const { t } = useI18n();
|
|
2085
|
+
return (jsxRuntime.jsx("div", { className: "str-video__participant-list--empty", children: t('participantList.noParticipantsFound.text', 'No participants found') }));
|
|
2080
2086
|
};
|
|
2081
2087
|
|
|
2082
2088
|
const SearchInput = ({ exitSearch, isActive, ...rest }) => {
|
|
@@ -2096,7 +2102,7 @@ const SearchInput = ({ exitSearch, isActive, ...rest }) => {
|
|
|
2096
2102
|
}, [inputElement]);
|
|
2097
2103
|
return (jsxRuntime.jsxs("div", { className: clsx('str-video__search-input__container', {
|
|
2098
2104
|
'str-video__search-input__container--active': isActive,
|
|
2099
|
-
}), children: [jsxRuntime.jsx("input", { placeholder: "Search", ...rest, ref: setInputElement }), isActive
|
|
2105
|
+
}), children: [jsxRuntime.jsx("span", { className: "str-video__search-input__icon" }), jsxRuntime.jsx("input", { placeholder: "Search", ...rest, ref: setInputElement }), isActive && (jsxRuntime.jsx("button", { className: "str-video__search-input__clear-btn", onClick: exitSearch, children: jsxRuntime.jsx("span", { className: "str-video__search-input__icon--active" }) }))] }));
|
|
2100
2106
|
};
|
|
2101
2107
|
|
|
2102
2108
|
function SearchResults({ EmptySearchResultComponent, LoadingIndicator: LoadingIndicator$1 = LoadingIndicator, searchQueryInProgress, searchResults, SearchResultList, }) {
|
|
@@ -2155,11 +2161,11 @@ const CallParticipantsList = ({ onClose, activeUsersSearchFn, blockedUsersSearch
|
|
|
2155
2161
|
};
|
|
2156
2162
|
const CallParticipantListContentHeader = ({ userListType, setUserListType, }) => {
|
|
2157
2163
|
const call = videoReactBindings.useCall();
|
|
2158
|
-
const { t } =
|
|
2164
|
+
const { t } = useI18n();
|
|
2159
2165
|
const muteAll = react.useCallback(() => {
|
|
2160
2166
|
call?.muteAllUsers('audio');
|
|
2161
2167
|
}, [call]);
|
|
2162
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__participant-list__content-header", children: [jsxRuntime.jsx("div", { className: "str-video__participant-list__content-header-title", children: userListType === 'active' && (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.MUTE_USERS], hasPermissionsOnly: true, children: jsxRuntime.jsx(
|
|
2168
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__participant-list__content-header", children: [jsxRuntime.jsx("div", { className: "str-video__participant-list__content-header-title", children: userListType === 'active' && (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.MUTE_USERS], hasPermissionsOnly: true, children: jsxRuntime.jsx(Button, { appearance: "ghost", size: "xs", variant: "secondary", onClick: muteAll, children: t('participantList.muteAll.label', 'Mute all') }) })) }), jsxRuntime.jsx(MenuToggle, { placement: "bottom-end", ToggleButton: ToggleButton$1, children: jsxRuntime.jsx(GenericMenu, { children: Object.keys(UserListTypes).map((lt) => (jsxRuntime.jsx(GenericMenuButtonItem, { "aria-current": lt === userListType, onClick: () => setUserListType(lt), children: UserListTypes[lt] }, lt))) }) })] }));
|
|
2163
2169
|
};
|
|
2164
2170
|
const ActiveUsersSearchResults = ({ searchQuery, activeUsersSearchFn: activeUsersSearchFnFromProps, debounceSearchInterval, }) => {
|
|
2165
2171
|
const { useParticipants } = videoReactBindings.useCallStateHooks();
|
|
@@ -2200,7 +2206,7 @@ const BlockedUsersSearchResults = ({ blockedUsersSearchFn: blockedUsersSearchFnF
|
|
|
2200
2206
|
return (jsxRuntime.jsx(SearchResults, { EmptySearchResultComponent: EmptyParticipantSearchList, LoadingIndicator: LoadingIndicator, searchQueryInProgress: searchQueryInProgress, searchResults: searchQuery ? searchResults : blockedUsers, SearchResultList: BlockedUserListing }));
|
|
2201
2207
|
};
|
|
2202
2208
|
const ToggleButton$1 = react.forwardRef(function ToggleButtonRender(props, ref) {
|
|
2203
|
-
return jsxRuntime.jsx(IconButton, {
|
|
2209
|
+
return (jsxRuntime.jsx(IconButton, { className: "str-video__participant-list__filter-button", active: props.menuShown, size: "sm", variant: "secondary", ref: ref, icon: "filter" }));
|
|
2204
2210
|
});
|
|
2205
2211
|
|
|
2206
2212
|
const CallPreview = (props) => {
|
|
@@ -2221,8 +2227,8 @@ const CallPreview = (props) => {
|
|
|
2221
2227
|
};
|
|
2222
2228
|
|
|
2223
2229
|
const CallRecordingListHeader = ({ callRecordings, onRefresh, }) => {
|
|
2224
|
-
const { t } =
|
|
2225
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__call-recording-list__header", children: [jsxRuntime.jsxs("div", { className: "str-video__call-recording-list__title", children: [jsxRuntime.jsx("span", { children: t('Call Recordings') }), callRecordings.length ? jsxRuntime.jsxs("span", { children: ["(", callRecordings.length, ")"] }) : null] }), onRefresh && (jsxRuntime.jsx(IconButton, {
|
|
2230
|
+
const { t } = useI18n();
|
|
2231
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__call-recording-list__header", children: [jsxRuntime.jsxs("div", { className: "str-video__call-recording-list__title", children: [jsxRuntime.jsx("span", { children: t('callRecordingList.callRecordings.title', 'Call Recordings') }), callRecordings.length ? jsxRuntime.jsxs("span", { children: ["(", callRecordings.length, ")"] }) : null] }), onRefresh && (jsxRuntime.jsx(IconButton, { size: "sm", variant: "secondary", title: t('callRecordingList.refresh.title', 'Refresh'), onClick: onRefresh, icon: "refresh" }))] }));
|
|
2226
2232
|
};
|
|
2227
2233
|
|
|
2228
2234
|
const dateFormat = (date) => {
|
|
@@ -2341,7 +2347,7 @@ const RingingCallControls = () => {
|
|
|
2341
2347
|
if (!call)
|
|
2342
2348
|
return null;
|
|
2343
2349
|
const buttonsDisabled = callCallingState !== videoClient.CallingState.RINGING;
|
|
2344
|
-
return (jsxRuntime.jsx("div", { className: "str-video__pending-call-controls", children: call.isCreatedByMe ? (jsxRuntime.jsx(CancelCallButton, { disabled: buttonsDisabled })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(AcceptCallButton, { disabled: buttonsDisabled }), jsxRuntime.jsx(CancelCallButton, { onClick: () => {
|
|
2350
|
+
return (jsxRuntime.jsx("div", { className: "str-video__pending-call-controls", children: call.isCreatedByMe ? (jsxRuntime.jsx(CancelCallButton, { size: "sm", disabled: buttonsDisabled })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(AcceptCallButton, { disabled: buttonsDisabled }), jsxRuntime.jsx(CancelCallButton, { size: "sm", onClick: () => {
|
|
2345
2351
|
const reason = call.isCreatedByMe ? 'cancel' : 'decline';
|
|
2346
2352
|
call.leave({ reject: true, reason }).catch((err) => {
|
|
2347
2353
|
console.error(`Failed to reject`, err);
|
|
@@ -2349,22 +2355,42 @@ const RingingCallControls = () => {
|
|
|
2349
2355
|
}, disabled: buttonsDisabled })] })) }));
|
|
2350
2356
|
};
|
|
2351
2357
|
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2358
|
+
/**
|
|
2359
|
+
* The label rendered for the current calling state.
|
|
2360
|
+
*
|
|
2361
|
+
* A `switch` of literal `t()` calls rather than a `Record<CallingState, string>` fed into a `t()`
|
|
2362
|
+
* lookup on a runtime value: the literal keys are statically extractable, which is what makes
|
|
2363
|
+
* `Migrating`, `Failed`, `Joined` and `Left call` translatable - none had a catalog entry before.
|
|
2364
|
+
* `IDLE` and `UNKNOWN` render nothing and get no key.
|
|
2365
|
+
*/
|
|
2366
|
+
const getCallingStateLabel = (callingState, t) => {
|
|
2367
|
+
switch (callingState) {
|
|
2368
|
+
case videoClient.CallingState.JOINING:
|
|
2369
|
+
return t('ringingCall.callingState.joining.text', 'Joining');
|
|
2370
|
+
case videoClient.CallingState.RINGING:
|
|
2371
|
+
return t('ringingCall.callingState.ringing.text', 'Ringing');
|
|
2372
|
+
case videoClient.CallingState.MIGRATING:
|
|
2373
|
+
return t('ringingCall.callingState.migrating.text', 'Migrating');
|
|
2374
|
+
case videoClient.CallingState.RECONNECTING:
|
|
2375
|
+
return t('ringingCall.callingState.reconnecting.text', 'Re-connecting');
|
|
2376
|
+
case videoClient.CallingState.RECONNECTING_FAILED:
|
|
2377
|
+
return t('ringingCall.callingState.reconnectingFailed.text', 'Failed');
|
|
2378
|
+
case videoClient.CallingState.OFFLINE:
|
|
2379
|
+
return t('ringingCall.callingState.offline.text', 'No internet connection');
|
|
2380
|
+
case videoClient.CallingState.JOINED:
|
|
2381
|
+
return t('ringingCall.callingState.joined.text', 'Joined');
|
|
2382
|
+
case videoClient.CallingState.LEFT:
|
|
2383
|
+
return t('ringingCall.callingState.left.text', 'Left call');
|
|
2384
|
+
case videoClient.CallingState.IDLE:
|
|
2385
|
+
case videoClient.CallingState.UNKNOWN:
|
|
2386
|
+
default:
|
|
2387
|
+
return undefined;
|
|
2388
|
+
}
|
|
2363
2389
|
};
|
|
2364
2390
|
const RingingCall = (props) => {
|
|
2365
2391
|
const { includeSelf = false, totalMembersToShow = 3 } = props;
|
|
2366
2392
|
const call = videoReactBindings.useCall();
|
|
2367
|
-
const { t } =
|
|
2393
|
+
const { t } = useI18n();
|
|
2368
2394
|
const { useCallCallingState, useCallMembers } = videoReactBindings.useCallStateHooks();
|
|
2369
2395
|
const callingState = useCallCallingState();
|
|
2370
2396
|
const members = useCallMembers();
|
|
@@ -2385,8 +2411,8 @@ const RingingCall = (props) => {
|
|
|
2385
2411
|
membersToShow.splice(0, 1, self.user);
|
|
2386
2412
|
}
|
|
2387
2413
|
}
|
|
2388
|
-
const callingStateLabel =
|
|
2389
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__call-panel str-video__call-panel--ringing", children: [jsxRuntime.jsx("div", { className: "str-video__call-panel__members-list", children: membersToShow.map((user) => (jsxRuntime.jsxs("div", { className: "str-video__call-panel__member-box", children: [jsxRuntime.jsx(Avatar, { name: user.name, imageSrc: user.image }), user.name && (jsxRuntime.jsx("div", { className: "str-video__member_details", children: jsxRuntime.jsx("span", { className: "str-video__member_name", children: user.name }) }))] }, user.id))) }), callingStateLabel && (jsxRuntime.jsx("div", { className: "str-video__call-panel__calling-state-label", children:
|
|
2414
|
+
const callingStateLabel = getCallingStateLabel(callingState, t);
|
|
2415
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__call-panel str-video__call-panel--ringing", children: [jsxRuntime.jsx("div", { className: "str-video__call-panel__members-list", children: membersToShow.map((user) => (jsxRuntime.jsxs("div", { className: "str-video__call-panel__member-box", children: [jsxRuntime.jsx(Avatar, { name: user.name, imageSrc: user.image }), user.name && (jsxRuntime.jsx("div", { className: "str-video__member_details", children: jsxRuntime.jsx("span", { className: "str-video__member_name", children: user.name }) }))] }, user.id))) }), callingStateLabel && (jsxRuntime.jsx("div", { className: "str-video__call-panel__calling-state-label", children: callingStateLabel })), [videoClient.CallingState.RINGING, videoClient.CallingState.JOINING].includes(callingState) && (jsxRuntime.jsx(RingingCallControls, {}))] }));
|
|
2390
2416
|
};
|
|
2391
2417
|
|
|
2392
2418
|
const byNameOrId = (a, b) => {
|
|
@@ -2438,7 +2464,7 @@ const PermissionRequests = () => {
|
|
|
2438
2464
|
// don't render anything if there are no permission requests
|
|
2439
2465
|
if (permissionRequests.length === 0)
|
|
2440
2466
|
return null;
|
|
2441
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__permission-requests", ref: refs.setReference, children: [jsxRuntime.jsxs("div", { className: "str-video__permission-requests__notification", children: [jsxRuntime.jsxs("span", { className: "str-video__permission-requests__notification__message", children: [permissionRequests.length, " pending permission requests"] }), jsxRuntime.jsx(Button, {
|
|
2467
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__permission-requests", ref: refs.setReference, children: [jsxRuntime.jsxs("div", { className: "str-video__permission-requests__notification", children: [jsxRuntime.jsxs("span", { className: "str-video__permission-requests__notification__message", children: [permissionRequests.length, " pending permission requests"] }), jsxRuntime.jsx(Button, { variant: "secondary", appearance: "outline", size: "sm", className: "str-video__permission-request__button", onClick: () => {
|
|
2442
2468
|
setExpanded((e) => !e);
|
|
2443
2469
|
}, children: expanded ? 'Hide requests' : 'Show requests' })] }), expanded && (jsxRuntime.jsx(PermissionRequestList, { ref: refs.setFloating, style: {
|
|
2444
2470
|
position: strategy,
|
|
@@ -2449,51 +2475,71 @@ const PermissionRequests = () => {
|
|
|
2449
2475
|
};
|
|
2450
2476
|
const PermissionRequestList = react.forwardRef(function PermissionRequestListRender(props, ref) {
|
|
2451
2477
|
const { permissionRequests, handleUpdatePermission, ...rest } = props;
|
|
2452
|
-
const { t } =
|
|
2478
|
+
const { t } = useI18n();
|
|
2453
2479
|
return (jsxRuntime.jsx("div", { className: "str-video__permission-requests-list", ref: ref, ...rest, children: permissionRequests.map((request, reqIndex) => {
|
|
2454
2480
|
const { user, permissions } = request;
|
|
2455
|
-
return (jsxRuntime.jsx(react.Fragment, { children: permissions.map((permission) => (jsxRuntime.jsxs("div", { className: "str-video__permission-request", children: [jsxRuntime.jsx("div", { className: "str-video__permission-request__message", children: messageForPermission(user.name || user.id, permission, t) }), jsxRuntime.jsx(Button, { className: "str-video__permission-request__button--allow",
|
|
2481
|
+
return (jsxRuntime.jsx(react.Fragment, { children: permissions.map((permission) => (jsxRuntime.jsxs("div", { className: "str-video__permission-request", children: [jsxRuntime.jsx("div", { className: "str-video__permission-request__message", children: messageForPermission(user.name || user.id, permission, t) }), jsxRuntime.jsx(Button, { variant: "primary", appearance: "solid", size: "sm", className: "str-video__permission-request__button str-video__permission-request__button--allow", onClick: handleUpdatePermission(request, 'grant'), children: t('common.allow.label', 'Allow') }), jsxRuntime.jsx(Button, { variant: "secondary", appearance: "outline", size: "sm", className: "str-video__permission-request__button str-video__permission-request__button--reject", onClick: handleUpdatePermission(request, 'revoke'), children: t('common.revoke.label', 'Revoke') }), jsxRuntime.jsx(Button, { variant: "secondary", appearance: "outline", size: "sm", className: "str-video__permission-request__button str-video__permission-request__button--reject", onClick: handleUpdatePermission(request, 'dismiss'), children: t('common.dismiss.label', 'Dismiss') })] }, permission))) }, `${user.id}/${reqIndex}`));
|
|
2456
2482
|
}) }));
|
|
2457
2483
|
});
|
|
2458
|
-
const Button = (props) => {
|
|
2459
|
-
const { className, ...rest } = props;
|
|
2460
|
-
return (jsxRuntime.jsx("button", { className: clsx('str-video__permission-request__button', className), ...rest }));
|
|
2461
|
-
};
|
|
2462
2484
|
const messageForPermission = (userName, permission, t) => {
|
|
2463
2485
|
switch (permission) {
|
|
2464
2486
|
case videoClient.OwnCapability.SEND_AUDIO:
|
|
2465
|
-
return t('{{ userName }} is requesting to speak', { userName });
|
|
2487
|
+
return t('permissions.requestingToSpeak.text', '{{ userName }} is requesting to speak', { userName });
|
|
2466
2488
|
case videoClient.OwnCapability.SEND_VIDEO:
|
|
2467
|
-
return t('{{ userName }} is requesting to share their camera', {
|
|
2489
|
+
return t('permissions.requestingCamera.text', '{{ userName }} is requesting to share their camera', {
|
|
2468
2490
|
userName,
|
|
2469
2491
|
});
|
|
2470
2492
|
case videoClient.OwnCapability.SCREENSHARE:
|
|
2471
|
-
return t('{{ userName }} is requesting to present their screen', {
|
|
2493
|
+
return t('permissions.requestingScreenShare.text', '{{ userName }} is requesting to present their screen', {
|
|
2472
2494
|
userName,
|
|
2473
2495
|
});
|
|
2474
2496
|
default:
|
|
2475
|
-
return t('{{ userName }} is requesting permission: {{ permission }}', {
|
|
2497
|
+
return t('permissions.requestingPermission.text', '{{ userName }} is requesting permission: {{ permission }}', {
|
|
2476
2498
|
userName,
|
|
2477
2499
|
permission,
|
|
2478
2500
|
});
|
|
2479
2501
|
}
|
|
2480
2502
|
};
|
|
2481
2503
|
|
|
2482
|
-
const StreamTheme = ({ as: Component = 'div', className, children, ...props }) => {
|
|
2483
|
-
return (jsxRuntime.jsx(Component, { ...props, className: clsx('str-video', className), children: children }));
|
|
2504
|
+
const StreamTheme = ({ as: Component = 'div', className, children, theme = 'str-video__theme-dark', ...props }) => {
|
|
2505
|
+
return (jsxRuntime.jsx(Component, { ...props, className: clsx('str-video', theme, className), children: children }));
|
|
2484
2506
|
};
|
|
2485
2507
|
|
|
2486
2508
|
const DefaultDisabledVideoPreview = () => {
|
|
2487
|
-
const { t } =
|
|
2488
|
-
return (jsxRuntime.jsx("div", { className: "str_video__video-preview__disabled-video-preview", children: t('Video is disabled') }));
|
|
2509
|
+
const { t } = useI18n();
|
|
2510
|
+
return (jsxRuntime.jsx("div", { className: "str_video__video-preview__disabled-video-preview", children: t('common.videoDisabled.text', 'Video is disabled') }));
|
|
2489
2511
|
};
|
|
2490
2512
|
const DefaultNoCameraPreview = () => {
|
|
2491
|
-
const { t } =
|
|
2492
|
-
return (jsxRuntime.jsx("div", { className: "str_video__video-preview__no-camera-preview", children: t('No camera found') }));
|
|
2513
|
+
const { t } = useI18n();
|
|
2514
|
+
return (jsxRuntime.jsx("div", { className: "str_video__video-preview__no-camera-preview", children: t('common.noCameraFound.text', 'No camera found') }));
|
|
2515
|
+
};
|
|
2516
|
+
/**
|
|
2517
|
+
* Reports whether the local user is currently speaking, before they join the
|
|
2518
|
+
* call. `MicrophoneManager` only runs its detector while the microphone is
|
|
2519
|
+
* muted (for `speakingWhileMuted`), so this mirrors `AudioVolumeIndicator` and
|
|
2520
|
+
* runs one on the live microphone stream instead.
|
|
2521
|
+
*/
|
|
2522
|
+
const useLocalSpeaking = (enabled) => {
|
|
2523
|
+
const { useMicrophoneState } = videoReactBindings.useCallStateHooks();
|
|
2524
|
+
const { isEnabled, mediaStream } = useMicrophoneState();
|
|
2525
|
+
const [isSpeaking, setIsSpeaking] = react.useState(false);
|
|
2526
|
+
react.useEffect(() => {
|
|
2527
|
+
if (!enabled || !isEnabled || !mediaStream) {
|
|
2528
|
+
setIsSpeaking(false);
|
|
2529
|
+
return;
|
|
2530
|
+
}
|
|
2531
|
+
const dispose = videoClient.createSoundDetector(mediaStream, ({ isSoundDetected }) => setIsSpeaking(isSoundDetected), { detectionFrequencyInMs: 80, destroyStreamOnStop: false });
|
|
2532
|
+
return () => {
|
|
2533
|
+
setIsSpeaking(false);
|
|
2534
|
+
dispose().catch(console.error);
|
|
2535
|
+
};
|
|
2536
|
+
}, [enabled, isEnabled, mediaStream]);
|
|
2537
|
+
return isSpeaking;
|
|
2493
2538
|
};
|
|
2494
|
-
const VideoPreview = ({ className, mirror = true, DisabledVideoPreview = DefaultDisabledVideoPreview, NoCameraPreview = DefaultNoCameraPreview, StartingCameraPreview = LoadingIndicator, }) => {
|
|
2539
|
+
const VideoPreview = ({ className, mirror = true, DisabledVideoPreview = DefaultDisabledVideoPreview, NoCameraPreview = DefaultNoCameraPreview, StartingCameraPreview = LoadingIndicator, speakingIndicatorVisible = false, }) => {
|
|
2495
2540
|
const { useCameraState } = videoReactBindings.useCallStateHooks();
|
|
2496
2541
|
const { devices, status, isMute, mediaStream } = useCameraState();
|
|
2542
|
+
const isSpeaking = useLocalSpeaking(speakingIndicatorVisible);
|
|
2497
2543
|
let contents;
|
|
2498
2544
|
if (isMute && devices?.length === 0) {
|
|
2499
2545
|
contents = jsxRuntime.jsx(NoCameraPreview, {});
|
|
@@ -2508,21 +2554,43 @@ const VideoPreview = ({ className, mirror = true, DisabledVideoPreview = Default
|
|
|
2508
2554
|
else {
|
|
2509
2555
|
contents = jsxRuntime.jsx(DisabledVideoPreview, {});
|
|
2510
2556
|
}
|
|
2511
|
-
return (jsxRuntime.jsx("div", { className: clsx('str-video__video-preview-container', className
|
|
2557
|
+
return (jsxRuntime.jsx("div", { className: clsx('str-video__video-preview-container', className, {
|
|
2558
|
+
'str-video__video-preview-container--speaking': isSpeaking,
|
|
2559
|
+
}), children: contents }));
|
|
2560
|
+
};
|
|
2561
|
+
|
|
2562
|
+
/** How many of the three bars are lit, per quality level. */
|
|
2563
|
+
const ACTIVE_BARS = {
|
|
2564
|
+
[videoClient.SfuModels.ConnectionQuality.POOR]: 1,
|
|
2565
|
+
[videoClient.SfuModels.ConnectionQuality.GOOD]: 2,
|
|
2566
|
+
[videoClient.SfuModels.ConnectionQuality.EXCELLENT]: 3,
|
|
2567
|
+
};
|
|
2568
|
+
const BAR_COUNT = 3;
|
|
2569
|
+
/**
|
|
2570
|
+
* Three ascending bars showing a participant's connection quality.
|
|
2571
|
+
*/
|
|
2572
|
+
const ConnectionQualityIndicator = ({ quality, title, className, }) => {
|
|
2573
|
+
const activeBars = ACTIVE_BARS[quality];
|
|
2574
|
+
if (!activeBars)
|
|
2575
|
+
return null;
|
|
2576
|
+
const level = videoClient.SfuModels.ConnectionQuality[quality].toLowerCase();
|
|
2577
|
+
return (jsxRuntime.jsx("span", { className: clsx('str-video__connection-quality-indicator', `str-video__connection-quality-indicator--${level}`, className), title: title ?? level, children: Array.from({ length: BAR_COUNT }, (_, index) => (jsxRuntime.jsx("span", { className: clsx('str-video__connection-quality-indicator__bar', index < activeBars &&
|
|
2578
|
+
'str-video__connection-quality-indicator__bar--active') }, index))) }));
|
|
2512
2579
|
};
|
|
2513
2580
|
|
|
2514
2581
|
const ToggleButton = react.forwardRef(function ToggleButtonRender(props, ref) {
|
|
2515
|
-
|
|
2582
|
+
const { t } = useI18n();
|
|
2583
|
+
return (jsxRuntime.jsx(IconButton, { className: "str-video__participant-view__menu-button", active: props.menuShown, size: "sm", variant: "secondary", ref: ref, title: t('participantView.moreOptions.title', 'More options'), icon: "ellipsis" }));
|
|
2516
2584
|
});
|
|
2517
2585
|
const DefaultScreenShareOverlay = () => {
|
|
2518
2586
|
const call = videoReactBindings.useCall();
|
|
2519
|
-
const { t } =
|
|
2587
|
+
const { t } = useI18n();
|
|
2520
2588
|
const stopScreenShare = () => {
|
|
2521
2589
|
call?.screenShare.disable().catch((err) => {
|
|
2522
2590
|
console.error('Failed to stop screen sharing:', err);
|
|
2523
2591
|
});
|
|
2524
2592
|
};
|
|
2525
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__screen-share-overlay", children: [jsxRuntime.jsx(Icon, { icon: "screen-share-off" }), jsxRuntime.jsx("span", { className: "str-video__screen-share-overlay__title", children: t('You are presenting your screen') }), jsxRuntime.jsxs(
|
|
2593
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__screen-share-overlay", children: [jsxRuntime.jsx(Icon, { icon: "screen-share-off" }), jsxRuntime.jsx("span", { className: "str-video__screen-share-overlay__title", children: t('common.presentingYourScreen.text', 'You are presenting your screen') }), jsxRuntime.jsxs(Button, { variant: "destructive", onClick: stopScreenShare, className: "str-video__screen-share-overlay__button", children: [jsxRuntime.jsx(Icon, { icon: "close" }), ' ', t('participantView.stopScreenSharing.label', 'Stop Screen Sharing')] })] }));
|
|
2526
2594
|
};
|
|
2527
2595
|
/**
|
|
2528
2596
|
* Rendered over a remote participant's tile when the browser's autoplay policy
|
|
@@ -2531,8 +2599,8 @@ const DefaultScreenShareOverlay = () => {
|
|
|
2531
2599
|
*/
|
|
2532
2600
|
const DefaultAudioBlockedNotification = () => {
|
|
2533
2601
|
const call = videoReactBindings.useCall();
|
|
2534
|
-
const { t } =
|
|
2535
|
-
return (jsxRuntime.jsx("button", { type: "button", className: "str-video__audio-blocked-notification", onClick: call?.resumeAudio, "aria-live": "polite", children: jsxRuntime.jsxs("span", { className: "str-video__audio-blocked-notification__message", children: [jsxRuntime.jsx(Icon, { icon: "speaker" }), jsxRuntime.jsxs("span", { className: "str-video__audio-blocked-notification__text", children: [jsxRuntime.jsx("span", { className: "str-video__audio-blocked-notification__title", children: t('Audio is blocked by your system') }), jsxRuntime.jsx("span", { className: "str-video__audio-blocked-notification__subtitle", children: t('Click or tap to play audio') })] })] }) }));
|
|
2602
|
+
const { t } = useI18n();
|
|
2603
|
+
return (jsxRuntime.jsx("button", { type: "button", className: "str-video__audio-blocked-notification", onClick: call?.resumeAudio, "aria-live": "polite", children: jsxRuntime.jsxs("span", { className: "str-video__audio-blocked-notification__message", children: [jsxRuntime.jsx(Icon, { icon: "speaker" }), jsxRuntime.jsxs("span", { className: "str-video__audio-blocked-notification__text", children: [jsxRuntime.jsx("span", { className: "str-video__audio-blocked-notification__title", children: t('participantView.audioBlocked.title', 'Audio is blocked by your system') }), jsxRuntime.jsx("span", { className: "str-video__audio-blocked-notification__subtitle", children: t('participantView.audioBlocked.description', 'Click or tap to play audio') })] })] }) }));
|
|
2536
2604
|
};
|
|
2537
2605
|
const DefaultParticipantViewUI = ({ indicatorsVisible = true, menuPlacement = 'bottom-start', showMenuButton = true, ParticipantActionsContextMenu: ParticipantActionsContextMenu$1 = ParticipantActionsContextMenu, AudioBlockedNotification = DefaultAudioBlockedNotification, }) => {
|
|
2538
2606
|
const { participant, trackType } = useParticipantViewContext();
|
|
@@ -2553,17 +2621,17 @@ const ParticipantDetails = ({ indicatorsVisible = true, }) => {
|
|
|
2553
2621
|
const { participant, trackType } = useParticipantViewContext();
|
|
2554
2622
|
const { isLocalParticipant, connectionQuality, pin, sessionId, name, userId, } = participant;
|
|
2555
2623
|
const call = videoReactBindings.useCall();
|
|
2556
|
-
const { t } =
|
|
2557
|
-
const connectionQualityAsString = !!connectionQuality &&
|
|
2558
|
-
videoClient.SfuModels.ConnectionQuality[connectionQuality].toLowerCase();
|
|
2624
|
+
const { t } = useI18n();
|
|
2559
2625
|
const hasAudioTrack = videoClient.hasAudio(participant);
|
|
2560
2626
|
const hasVideoTrack = videoClient.hasVideo(participant);
|
|
2561
2627
|
const canUnpin = !!pin && pin.isLocalPin;
|
|
2562
2628
|
const isTrackPaused = trackType !== 'none' ? videoClient.hasPausedTrack(participant, trackType) : false;
|
|
2563
2629
|
const isAudioConnecting = videoReactBindings.useIsAudioConnecting(participant);
|
|
2564
2630
|
const isVideoConnecting = videoReactBindings.useIsVideoConnecting(participant);
|
|
2565
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "str-video__participant-details", children: jsxRuntime.jsxs("div", { className: "str-video__participant-details__name", children: [name || userId, indicatorsVisible && isAudioConnecting && (jsxRuntime.jsx(LoadingIndicator, { className: "str-video__participant-details__name--audio-connecting", tooltip: t('Audio is connecting...') })), indicatorsVisible && !hasAudioTrack && (jsxRuntime.jsx("span", { className: "str-video__participant-details__name--audio-muted" })), indicatorsVisible && isVideoConnecting && (jsxRuntime.jsx(LoadingIndicator, { className: "str-video__participant-details__name--video-connecting", tooltip: t('Video is connecting...') })), indicatorsVisible && !hasVideoTrack && (jsxRuntime.jsx("span", { className: "str-video__participant-details__name--video-muted" })), indicatorsVisible && isTrackPaused && (jsxRuntime.jsx("span", { title: t('Video paused due to insufficient bandwidth'), className: "str-video__participant-details__name--track-paused" })), indicatorsVisible && pin && (jsxRuntime.jsx("span", { title: canUnpin
|
|
2566
|
-
|
|
2631
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "str-video__participant-details", children: jsxRuntime.jsxs("div", { className: "str-video__participant-details__name", children: [jsxRuntime.jsx("span", { className: "str-video__participant-details__name-text", children: name || userId }), indicatorsVisible && isAudioConnecting && (jsxRuntime.jsx(LoadingIndicator, { className: "str-video__participant-details__name--audio-connecting", tooltip: t('participantView.audioConnecting.title', 'Audio is connecting...') })), indicatorsVisible && !hasAudioTrack && (jsxRuntime.jsx("span", { className: "str-video__participant-details__name--audio-muted" })), indicatorsVisible && isVideoConnecting && (jsxRuntime.jsx(LoadingIndicator, { className: "str-video__participant-details__name--video-connecting", tooltip: t('participantView.videoConnecting.title', 'Video is connecting...') })), indicatorsVisible && !hasVideoTrack && (jsxRuntime.jsx("span", { className: "str-video__participant-details__name--video-muted" })), indicatorsVisible && isTrackPaused && (jsxRuntime.jsx("span", { title: t('participantView.videoPausedInsufficientBandwidth.title', 'Video paused due to insufficient bandwidth'), className: "str-video__participant-details__name--track-paused" })), indicatorsVisible && pin && (jsxRuntime.jsx("span", { title: canUnpin
|
|
2632
|
+
? t('participantView.unpin.label', 'Unpin')
|
|
2633
|
+
: t('participantList.pinned.title', 'Pinned'), onClick: canUnpin ? () => call?.unpin(sessionId) : undefined, className: "str-video__participant-details__name--pinned" })), indicatorsVisible && jsxRuntime.jsx(SpeechIndicator, {})] }) }), indicatorsVisible && (jsxRuntime.jsx(Notification, { state: "error", isVisible: isLocalParticipant &&
|
|
2634
|
+
connectionQuality === videoClient.SfuModels.ConnectionQuality.POOR, message: t('participantView.connectionQuality.poor.text', 'Poor connection quality. Please check your internet connection.'), children: connectionQuality && (jsxRuntime.jsx(ConnectionQualityIndicator, { quality: connectionQuality })) }))] }));
|
|
2567
2635
|
};
|
|
2568
2636
|
const SpeechIndicator = () => {
|
|
2569
2637
|
const { participant } = useParticipantViewContext();
|
|
@@ -2613,7 +2681,7 @@ const ParticipantView = react.memo(react.forwardRef(function ParticipantViewRend
|
|
|
2613
2681
|
applyElementToRef(ref, element);
|
|
2614
2682
|
setTrackedElement(element);
|
|
2615
2683
|
}, className: clsx('str-video__participant-view', isDominantSpeaker &&
|
|
2616
|
-
'str-video__participant-view--dominant-speaker', isSpeaking && 'str-video__participant-view--speaking', !hasVideoTrack && 'str-video__participant-view--no-video', !hasAudioTrack && 'str-video__participant-view--no-audio', className), children: jsxRuntime.jsxs(ParticipantViewContext.Provider, { value: participantViewContextValue, children: [!isLocalParticipant && !muteAudio && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [hasAudioTrack && (jsxRuntime.jsx(Audio, { participant: participant, trackType: "audioTrack" })), hasScreenShareAudioTrack && (jsxRuntime.jsx(Audio, { participant: participant, trackType: "screenShareAudioTrack" }))] })), jsxRuntime.jsx(Video
|
|
2684
|
+
'str-video__participant-view--dominant-speaker', isSpeaking && 'str-video__participant-view--speaking', !hasVideoTrack && 'str-video__participant-view--no-video', !hasAudioTrack && 'str-video__participant-view--no-audio', className), children: jsxRuntime.jsxs(ParticipantViewContext.Provider, { value: participantViewContextValue, children: [!isLocalParticipant && !muteAudio && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [hasAudioTrack && (jsxRuntime.jsx(Audio, { participant: participant, trackType: "audioTrack" })), hasScreenShareAudioTrack && (jsxRuntime.jsx(Audio, { participant: participant, trackType: "screenShareAudioTrack" }))] })), jsxRuntime.jsx(Video, { VideoPlaceholder: VideoPlaceholder, PictureInPicturePlaceholder: PictureInPicturePlaceholder, participant: participant, trackType: trackType, refs: videoRefs, enabled: isLocalParticipant ||
|
|
2617
2685
|
trackType !== 'videoTrack' ||
|
|
2618
2686
|
isParticipantVideoEnabled(participant.sessionId), mirror: mirror, autoPlay: true }), isComponentType(ParticipantViewUI) ? (jsxRuntime.jsx(ParticipantViewUI, {})) : (ParticipantViewUI)] }) }));
|
|
2619
2687
|
}));
|
|
@@ -2623,185 +2691,27 @@ ParticipantView.displayName = 'ParticipantView';
|
|
|
2623
2691
|
const StreamCall = videoReactBindings.StreamCallProvider;
|
|
2624
2692
|
StreamCall.displayName = 'StreamCall';
|
|
2625
2693
|
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
var Block = "Block";
|
|
2648
|
-
var Kick = "Kick";
|
|
2649
|
-
var Enter = "Enter";
|
|
2650
|
-
var Leave = "Leave";
|
|
2651
|
-
var Participants = "Participants";
|
|
2652
|
-
var Anonymous = ", and ({{ count }}) anonymous";
|
|
2653
|
-
var Speaker = "Speaker";
|
|
2654
|
-
var Microphone = "Microphone";
|
|
2655
|
-
var Backstage = "Backstage";
|
|
2656
|
-
var en = {
|
|
2657
|
-
Joining: Joining,
|
|
2658
|
-
Mic: Mic,
|
|
2659
|
-
"No internet connection": "No internet connection",
|
|
2660
|
-
"Re-connecting": "Re-connecting",
|
|
2661
|
-
Ringing: Ringing,
|
|
2662
|
-
"Screen Share": "Screen Share",
|
|
2663
|
-
"Select a Camera": "Select a Camera",
|
|
2664
|
-
"Select a Mic": "Select a Mic",
|
|
2665
|
-
"Select Speakers": "Select Speakers",
|
|
2666
|
-
Speakers: Speakers,
|
|
2667
|
-
Video: Video,
|
|
2668
|
-
"You are muted. Unmute to speak.": "You are muted. Unmute to speak.",
|
|
2669
|
-
"Background filters performance is degraded. Consider disabling filters for better performance.": "Background filters performance is degraded. Consider disabling filters for better performance.",
|
|
2670
|
-
Live: Live,
|
|
2671
|
-
"Livestream starts soon": "Livestream starts soon",
|
|
2672
|
-
"Livestream starts at {{ time }}": "Livestream starts at {{ time }}",
|
|
2673
|
-
"{{ count }} participants joined early_one": "{{ count }} participant joined early",
|
|
2674
|
-
"{{ count }} participants joined early_other": "{{ count }} participants joined early",
|
|
2675
|
-
"You can now speak.": "You can now speak.",
|
|
2676
|
-
"Awaiting for an approval to speak.": "Awaiting for an approval to speak.",
|
|
2677
|
-
"You can no longer speak.": "You can no longer speak.",
|
|
2678
|
-
"You can now share your video.": "You can now share your video.",
|
|
2679
|
-
"Awaiting for an approval to share your video.": "Awaiting for an approval to share your video.",
|
|
2680
|
-
"You can no longer share your video.": "You can no longer share your video.",
|
|
2681
|
-
"Waiting for recording to stop...": "Waiting for recording to stop...",
|
|
2682
|
-
"Waiting for recording to start...": "Waiting for recording to start...",
|
|
2683
|
-
"Record call": "Record call",
|
|
2684
|
-
Reactions: Reactions,
|
|
2685
|
-
Statistics: Statistics,
|
|
2686
|
-
"You can now share your screen.": "You can now share your screen.",
|
|
2687
|
-
"Awaiting for an approval to share screen.": "Awaiting for an approval to share screen.",
|
|
2688
|
-
"You can no longer share your screen.": "You can no longer share your screen.",
|
|
2689
|
-
"Share screen": "Share screen",
|
|
2690
|
-
"Incoming Call...": "Incoming Call...",
|
|
2691
|
-
"Calling...": "Calling...",
|
|
2692
|
-
"Mute All": "Mute All",
|
|
2693
|
-
Invite: Invite,
|
|
2694
|
-
Join: Join,
|
|
2695
|
-
You: You,
|
|
2696
|
-
Me: Me,
|
|
2697
|
-
Unknown: Unknown,
|
|
2698
|
-
"Toggle device menu": "Toggle device menu",
|
|
2699
|
-
Default: Default,
|
|
2700
|
-
"Call Recordings": "Call Recordings",
|
|
2701
|
-
Refresh: Refresh,
|
|
2702
|
-
"Check your browser video permissions": "Check your browser video permissions",
|
|
2703
|
-
"Video publishing is disabled by the system": "Video publishing is disabled by the system",
|
|
2704
|
-
"You have no permission to share your video": "You have no permission to share your video",
|
|
2705
|
-
"You have no permission to share your audio": "You have no permission to share your audio",
|
|
2706
|
-
"You are presenting your screen": "You are presenting your screen",
|
|
2707
|
-
"Stop Screen Sharing": "Stop Screen Sharing",
|
|
2708
|
-
"Audio is blocked by your system": "Audio is blocked by your system",
|
|
2709
|
-
"Click or tap to play audio": "Click or tap to play audio",
|
|
2710
|
-
Allow: Allow,
|
|
2711
|
-
Revoke: Revoke,
|
|
2712
|
-
Dismiss: Dismiss,
|
|
2713
|
-
"Microphone on": "Microphone on",
|
|
2714
|
-
"Microphone off": "Microphone off",
|
|
2715
|
-
"Microphone is paused by your system": "Microphone is paused by your system",
|
|
2716
|
-
"Camera on": "Camera on",
|
|
2717
|
-
"Camera off": "Camera off",
|
|
2718
|
-
"Camera is paused by your system": "Camera is paused by your system",
|
|
2719
|
-
"No camera found": "No camera found",
|
|
2720
|
-
"Video is disabled": "Video is disabled",
|
|
2721
|
-
Pinned: Pinned,
|
|
2722
|
-
Unpin: Unpin,
|
|
2723
|
-
Pin: Pin,
|
|
2724
|
-
"Pin for everyone": "Pin for everyone",
|
|
2725
|
-
"Unpin for everyone": "Unpin for everyone",
|
|
2726
|
-
Block: Block,
|
|
2727
|
-
Kick: Kick,
|
|
2728
|
-
"Turn off video": "Turn off video",
|
|
2729
|
-
"Turn off screen share": "Turn off screen share",
|
|
2730
|
-
"Mute audio": "Mute audio",
|
|
2731
|
-
"Mute screen share audio": "Mute screen share audio",
|
|
2732
|
-
"Allow audio": "Allow audio",
|
|
2733
|
-
"Allow video": "Allow video",
|
|
2734
|
-
"Allow screen sharing": "Allow screen sharing",
|
|
2735
|
-
"Disable audio": "Disable audio",
|
|
2736
|
-
"Disable video": "Disable video",
|
|
2737
|
-
"Disable screen sharing": "Disable screen sharing",
|
|
2738
|
-
Enter: Enter,
|
|
2739
|
-
Leave: Leave,
|
|
2740
|
-
"Leave call": "Leave call",
|
|
2741
|
-
"End call for all": "End call for all",
|
|
2742
|
-
"{{ direction }} fullscreen": "{{ direction }} fullscreen",
|
|
2743
|
-
"{{ direction }} picture-in-picture": "{{ direction }} picture-in-picture",
|
|
2744
|
-
"Dominant Speaker": "Dominant Speaker",
|
|
2745
|
-
"Poor connection quality": "Poor connection quality. Please check your internet connection.",
|
|
2746
|
-
"Video paused due to insufficient bandwidth": "Video paused due to insufficient bandwidth",
|
|
2747
|
-
"Audio is connecting...": "Audio is connecting...",
|
|
2748
|
-
"Video is connecting...": "Video is connecting...",
|
|
2749
|
-
Participants: Participants,
|
|
2750
|
-
Anonymous: Anonymous,
|
|
2751
|
-
"No participants found": "No participants found",
|
|
2752
|
-
"Participants ({{ numberOfParticipants }})": "Participants ({{ numberOfParticipants }})",
|
|
2753
|
-
"{{ userName }} is sharing their screen": "{{ userName }} is sharing their screen",
|
|
2754
|
-
"{{ userName }} is requesting to speak": "{{ userName }} is requesting to speak",
|
|
2755
|
-
"{{ userName }} is requesting to share their camera": "{{ userName }} is requesting to share their camera",
|
|
2756
|
-
"{{ userName }} is requesting to present their screen": "{{ userName }} is requesting to present their screen",
|
|
2757
|
-
"{{ userName }} is requesting permission: {{ permission }}": "{{ userName }} is requesting permission: {{ permission }}",
|
|
2758
|
-
"Applying...": "Applying...",
|
|
2759
|
-
"Disable blur": "Disable blur",
|
|
2760
|
-
"Blur background": "Blur background",
|
|
2761
|
-
"Migrating...": "Migrating...",
|
|
2762
|
-
"Reconnecting...": "Reconnecting...",
|
|
2763
|
-
"You are offline. Check your internet connection.": "You are offline. Check your internet connection.",
|
|
2764
|
-
"Failed to restore connection. Please try again.": "Failed to restore connection. Please try again.",
|
|
2765
|
-
"Failed to join. Please try again.": "Failed to join. Please try again.",
|
|
2766
|
-
"Set up your call before joining": "Set up your call before joining",
|
|
2767
|
-
"Please grant your browser permission to access your camera and microphone.": "Please grant your browser permission to access your camera and microphone.",
|
|
2768
|
-
"Start call": "Start call",
|
|
2769
|
-
Speaker: Speaker,
|
|
2770
|
-
Microphone: Microphone,
|
|
2771
|
-
Backstage: Backstage,
|
|
2772
|
-
"Go Live": "Go Live",
|
|
2773
|
-
"Stop Live": "End Live",
|
|
2774
|
-
"Enter Backstage": "Enter Backstage",
|
|
2775
|
-
"Prepare your livestream": "Prepare your livestream",
|
|
2776
|
-
"Ready to go live": "Ready to go live",
|
|
2777
|
-
"Stream is ready!": "Stream is ready!",
|
|
2778
|
-
"Waiting for the livestream to start": "Waiting for the livestream to start",
|
|
2779
|
-
"{{ count }} waiting": "{{ count }} waiting",
|
|
2780
|
-
"Join Stream": "Join Stream",
|
|
2781
|
-
"Join automatically when stream starts": "Join automatically when stream starts",
|
|
2782
|
-
"Display name": "Display name",
|
|
2783
|
-
"Permission needed": "Permission needed",
|
|
2784
|
-
"Call ended": "Call ended",
|
|
2785
|
-
"Rejoin call": "Rejoin call",
|
|
2786
|
-
"Left by mistake?": "Left by mistake?",
|
|
2787
|
-
"Help us improve": "Help us improve",
|
|
2788
|
-
"Leave feedback": "Leave feedback",
|
|
2789
|
-
"Failed to rejoin. Please try again.": "Failed to rejoin. Please try again.",
|
|
2790
|
-
"Share your feedback": "Share your feedback",
|
|
2791
|
-
"Tell us about your experience...": "Tell us about your experience...",
|
|
2792
|
-
"Submit feedback": "Submit feedback",
|
|
2793
|
-
"Feedback message": "Feedback message",
|
|
2794
|
-
"How was your call quality?": "How was your call quality?",
|
|
2795
|
-
"Rate {{ count }} star_one": "Rate {{ count }} star",
|
|
2796
|
-
"Rate {{ count }} star_other": "Rate {{ count }} stars",
|
|
2797
|
-
"Thank you!": "Thank you!",
|
|
2798
|
-
"Your feedback helps improve call quality.": "Your feedback helps improve call quality."
|
|
2799
|
-
};
|
|
2800
|
-
|
|
2801
|
-
const translations = { en };
|
|
2802
|
-
|
|
2803
|
-
const StreamVideo = (props) => {
|
|
2804
|
-
return (jsxRuntime.jsx(videoReactBindings.StreamVideoProvider, { translationsOverrides: translations, ...props }));
|
|
2694
|
+
/**
|
|
2695
|
+
* StreamVideo is the root provider of the SDK: it provides the client to the component tree and
|
|
2696
|
+
* mounts the SDK's translation context.
|
|
2697
|
+
*
|
|
2698
|
+
* The i18n runtime lives here rather than in `@stream-io/video-react-bindings` because the key
|
|
2699
|
+
* catalog is generated from *this* package's `t()` call sites.
|
|
2700
|
+
*
|
|
2701
|
+
* This also fixes a real bug in the previous implementation, which rendered
|
|
2702
|
+
* `<StreamVideoProvider translationsOverrides={translations} {...props} />`. Because `{...props}`
|
|
2703
|
+
* came last, an integrator passing `translationsOverrides` *replaced* the SDK's bundled strings
|
|
2704
|
+
* instead of merging with them, leaving every untranslated key rendering as a raw dotted path.
|
|
2705
|
+
* `useStreami18n` layers integrator dictionaries over the SDK's own defaults, so a partial
|
|
2706
|
+
* dictionary is now safe.
|
|
2707
|
+
*/
|
|
2708
|
+
const StreamVideo = ({ children, client, i18nInstance, language, translations, }) => {
|
|
2709
|
+
const translationContext = useStreami18n({
|
|
2710
|
+
i18nInstance,
|
|
2711
|
+
language,
|
|
2712
|
+
translations,
|
|
2713
|
+
});
|
|
2714
|
+
return (jsxRuntime.jsx(videoReactBindings.StreamVideoProvider, { client: client, children: jsxRuntime.jsx(TranslationProvider, { value: translationContext, children: children }) }));
|
|
2805
2715
|
};
|
|
2806
2716
|
StreamVideo.displayName = 'StreamVideo';
|
|
2807
2717
|
|
|
@@ -2982,7 +2892,7 @@ const BackstageLayout = (props) => {
|
|
|
2982
2892
|
const { useParticipantCount, useCallStartsAt } = videoReactBindings.useCallStateHooks();
|
|
2983
2893
|
const participantCount = useParticipantCount();
|
|
2984
2894
|
const startsAt = useCallStartsAt();
|
|
2985
|
-
const { t } =
|
|
2895
|
+
const { t } = useI18n();
|
|
2986
2896
|
const [startsAtPassed, setStartsAtPassed] = react.useState(() => !!startsAt && startsAt.getTime() < Date.now());
|
|
2987
2897
|
react.useEffect(() => {
|
|
2988
2898
|
if (!startsAt || startsAtPassed)
|
|
@@ -2996,17 +2906,20 @@ const BackstageLayout = (props) => {
|
|
|
2996
2906
|
return () => clearInterval(interval);
|
|
2997
2907
|
}, [startsAt, startsAtPassed]);
|
|
2998
2908
|
return (jsxRuntime.jsx("div", { className: "str-video__livestream-layout__wrapper", children: jsxRuntime.jsxs("div", { className: "str-video__livestream-layout__backstage", children: [startsAt && (jsxRuntime.jsx("span", { className: "str-video__livestream-layout__starts-at", children: startsAtPassed
|
|
2999
|
-
? t('Livestream starts soon')
|
|
3000
|
-
: t('Livestream starts at {{ time }}', {
|
|
2909
|
+
? t('livestream.backstage.startsSoon.text', 'Livestream starts soon')
|
|
2910
|
+
: t('livestream.backstage.startsAt.text', 'Livestream starts at {{ time }}', {
|
|
3001
2911
|
time: startsAt.toLocaleTimeString([], {
|
|
3002
2912
|
hour: '2-digit',
|
|
3003
2913
|
minute: '2-digit',
|
|
3004
2914
|
}),
|
|
3005
|
-
}) })), showEarlyParticipantCount && (jsxRuntime.
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
2915
|
+
}) })), showEarlyParticipantCount && (jsxRuntime.jsxs("span", { className: "str-video__livestream-layout__early-viewers-count", children: [jsxRuntime.jsx(Icon, { icon: "livestream-viewers" }), t('livestream.backstage.participantsJoinedEarly.text', {
|
|
2916
|
+
count: participantCount,
|
|
2917
|
+
formattedCount: humanizeParticipantCount
|
|
2918
|
+
? videoClient.humanize(participantCount)
|
|
2919
|
+
: participantCount,
|
|
2920
|
+
defaultValue_one: '{{ formattedCount }} participant joined early',
|
|
2921
|
+
defaultValue_other: '{{ formattedCount }} participants joined early',
|
|
2922
|
+
})] }))] }) }));
|
|
3010
2923
|
};
|
|
3011
2924
|
BackstageLayout.displayName = 'BackstageLayout';
|
|
3012
2925
|
const ParticipantOverlay = (props) => {
|
|
@@ -3024,14 +2937,14 @@ const ParticipantOverlay = (props) => {
|
|
|
3024
2937
|
const toggleFullScreen = useToggleFullScreen();
|
|
3025
2938
|
const { speaker, volume } = useSpeakerState();
|
|
3026
2939
|
const isSpeakerMuted = volume === 0;
|
|
3027
|
-
const { t } =
|
|
3028
|
-
return (jsxRuntime.jsx("div", { className: "str-video__livestream-layout__overlay", children: overlayBarVisible && (jsxRuntime.jsxs("div", { className: "str-video__livestream-layout__overlay__bar", children: [jsxRuntime.jsxs("div", { className: "str-video__livestream-layout__overlay__bar-left", children: [showLiveBadge && (jsxRuntime.
|
|
3029
|
-
|
|
3030
|
-
|
|
2940
|
+
const { t } = useI18n();
|
|
2941
|
+
return (jsxRuntime.jsx("div", { className: "str-video__livestream-layout__overlay", children: overlayBarVisible && (jsxRuntime.jsxs("div", { className: "str-video__livestream-layout__overlay__bar", children: [jsxRuntime.jsxs("div", { className: "str-video__livestream-layout__overlay__bar-left", children: [showLiveBadge && (jsxRuntime.jsxs("span", { className: "str-video__livestream-layout__live-badge", children: [jsxRuntime.jsx("span", { className: "str-video__livestream-layout__live-badge__dot", "aria-hidden": "true" }), t('common.live.label', 'Live')] })), showParticipantCount && (jsxRuntime.jsxs("span", { className: "str-video__livestream-layout__viewers-count", children: [jsxRuntime.jsx(Icon, { icon: "livestream-viewers" }), humanizeParticipantCount
|
|
2942
|
+
? videoClient.humanize(participantCount)
|
|
2943
|
+
: participantCount] })), showSpeakerName && (jsxRuntime.jsx("span", { className: "str-video__livestream-layout__speaker-name", title: participant.name || participant.userId || '', children: jsxRuntime.jsx("span", { children: participant.name || participant.userId || '' }) }))] }), jsxRuntime.jsx("div", { className: "str-video__livestream-layout__overlay__bar-center", children: showDuration && (jsxRuntime.jsx("span", { className: "str-video__livestream-layout__duration", children: formatDuration(duration) })) }), jsxRuntime.jsxs("div", { className: "str-video__livestream-layout__overlay__bar-right", children: [showMuteButton && (jsxRuntime.jsx(IconButton, { icon: isSpeakerMuted ? 'speaker-off' : 'speaker', variant: "secondary", appearance: "solid", size: "sm", className: clsx('str-video__livestream-layout__mute-button', isSpeakerMuted &&
|
|
3031
2944
|
'str-video__livestream-layout__mute-button--muted'), onClick: () => speaker.setVolume(isSpeakerMuted ? 1 : 0) })), enableFullScreen &&
|
|
3032
2945
|
participantViewElement &&
|
|
3033
2946
|
typeof participantViewElement.requestFullscreen !==
|
|
3034
|
-
'undefined' && (jsxRuntime.jsx("
|
|
2947
|
+
'undefined' && (jsxRuntime.jsx(IconButton, { icon: "fullscreen", variant: "secondary", appearance: "solid", size: "sm", className: "str-video__livestream-layout__go-fullscreen", onClick: toggleFullScreen }))] })] })) }));
|
|
3035
2948
|
};
|
|
3036
2949
|
const useUpdateCallDuration = () => {
|
|
3037
2950
|
const { useIsCallLive, useCallSession } = videoReactBindings.useCallStateHooks();
|
|
@@ -3096,6 +3009,7 @@ const PaginatedGridLayoutGroup = ({ group, mirror, VideoPlaceholder, PictureInPi
|
|
|
3096
3009
|
}), children: group.map((participant) => (jsxRuntime.jsx(ParticipantView, { participant: participant, muteAudio: true, mirror: mirror, VideoPlaceholder: VideoPlaceholder, PictureInPicturePlaceholder: PictureInPicturePlaceholder, ParticipantViewUI: ParticipantViewUI }, participant.sessionId))) }));
|
|
3097
3010
|
};
|
|
3098
3011
|
const PaginatedGridLayout = (props) => {
|
|
3012
|
+
const { t } = useI18n();
|
|
3099
3013
|
const { groupSize = (props.groupSize || 0) > 0
|
|
3100
3014
|
? props.groupSize || GROUP_SIZE
|
|
3101
3015
|
: GROUP_SIZE, excludeLocalParticipant = false, filterParticipants, mirrorLocalParticipantVideo = true, pageArrowsVisible = true, VideoPlaceholder, ParticipantViewUI = DefaultParticipantViewUI, PictureInPicturePlaceholder, muted, } = props;
|
|
@@ -3127,7 +3041,7 @@ const PaginatedGridLayout = (props) => {
|
|
|
3127
3041
|
const mirror = mirrorLocalParticipantVideo ? undefined : false;
|
|
3128
3042
|
if (!call)
|
|
3129
3043
|
return null;
|
|
3130
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__paginated-grid-layout__wrapper", ref: setPaginatedGridLayoutWrapperElement, children: [!muted && jsxRuntime.jsx(ParticipantsAudio, { participants: remoteParticipants }), jsxRuntime.jsxs("div", { className: "str-video__paginated-grid-layout", children: [pageArrowsVisible && pageCount > 1 && (jsxRuntime.jsx(IconButton, { icon: "caret-left", disabled: page === 0, onClick: () => setPage((currentPage) => Math.max(0, currentPage - 1)) })), selectedGroup && (jsxRuntime.jsx(PaginatedGridLayoutGroup, { group: selectedGroup, mirror: mirror, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI, PictureInPicturePlaceholder: PictureInPicturePlaceholder })), pageArrowsVisible && pageCount > 1 && (jsxRuntime.jsx(IconButton, { disabled: page === pageCount - 1, icon: "caret-right", onClick: () => setPage((currentPage) => Math.min(pageCount - 1, currentPage + 1)) }))] })] }));
|
|
3044
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__paginated-grid-layout__wrapper", ref: setPaginatedGridLayoutWrapperElement, children: [!muted && jsxRuntime.jsx(ParticipantsAudio, { participants: remoteParticipants }), jsxRuntime.jsxs("div", { className: "str-video__paginated-grid-layout", children: [pageArrowsVisible && pageCount > 1 && (jsxRuntime.jsx(IconButton, { size: "sm", variant: "secondary", icon: "caret-left", "aria-label": t('callLayout.paginatedGridLayout.previousPage.ariaLabel', 'Previous page'), disabled: page === 0, onClick: () => setPage((currentPage) => Math.max(0, currentPage - 1)) })), selectedGroup && (jsxRuntime.jsx(PaginatedGridLayoutGroup, { group: selectedGroup, mirror: mirror, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI, PictureInPicturePlaceholder: PictureInPicturePlaceholder })), pageArrowsVisible && pageCount > 1 && (jsxRuntime.jsx(IconButton, { size: "sm", variant: "secondary", disabled: page === pageCount - 1, icon: "caret-right", "aria-label": t('callLayout.paginatedGridLayout.nextPage.ariaLabel', 'Next page'), onClick: () => setPage((currentPage) => Math.min(pageCount - 1, currentPage + 1)) }))] })] }));
|
|
3131
3045
|
};
|
|
3132
3046
|
PaginatedGridLayout.displayName = 'PaginatedGridLayout';
|
|
3133
3047
|
|
|
@@ -3232,6 +3146,7 @@ const SpeakerLayout = ({ ParticipantViewUIBar = DefaultParticipantViewUIBar, Par
|
|
|
3232
3146
|
};
|
|
3233
3147
|
SpeakerLayout.displayName = 'SpeakerLayout';
|
|
3234
3148
|
const HorizontalScrollButtons = ({ scrollWrapper, }) => {
|
|
3149
|
+
const { t } = useI18n();
|
|
3235
3150
|
const scrollPosition = useHorizontalScrollPosition(scrollWrapper);
|
|
3236
3151
|
const scrollStartClickHandler = () => {
|
|
3237
3152
|
scrollWrapper?.scrollBy({ left: -150, behavior: 'smooth' });
|
|
@@ -3239,9 +3154,10 @@ const HorizontalScrollButtons = ({ scrollWrapper, }) => {
|
|
|
3239
3154
|
const scrollEndClickHandler = () => {
|
|
3240
3155
|
scrollWrapper?.scrollBy({ left: 150, behavior: 'smooth' });
|
|
3241
3156
|
};
|
|
3242
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [scrollPosition && scrollPosition !== 'start' && (jsxRuntime.jsx(IconButton, { onClick: scrollStartClickHandler, icon: "caret-left", className: "str-video__speaker-layout__participants-bar--button-left" })), scrollPosition && scrollPosition !== 'end' && (jsxRuntime.jsx(IconButton, { onClick: scrollEndClickHandler, icon: "caret-right", className: "str-video__speaker-layout__participants-bar--button-right" }))] }));
|
|
3157
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [scrollPosition && scrollPosition !== 'start' && (jsxRuntime.jsx(IconButton, { size: "sm", variant: "secondary", onClick: scrollStartClickHandler, icon: "caret-left", "aria-label": t('callLayout.speakerLayout.scrollParticipantsLeft.ariaLabel', 'Scroll participants left'), className: "str-video__speaker-layout__participants-bar--button-left" })), scrollPosition && scrollPosition !== 'end' && (jsxRuntime.jsx(IconButton, { size: "sm", variant: "secondary", onClick: scrollEndClickHandler, icon: "caret-right", "aria-label": t('callLayout.speakerLayout.scrollParticipantsRight.ariaLabel', 'Scroll participants right'), className: "str-video__speaker-layout__participants-bar--button-right" }))] }));
|
|
3243
3158
|
};
|
|
3244
3159
|
const VerticalScrollButtons = ({ scrollWrapper, }) => {
|
|
3160
|
+
const { t } = useI18n();
|
|
3245
3161
|
const scrollPosition = useVerticalScrollPosition(scrollWrapper);
|
|
3246
3162
|
const scrollTopClickHandler = () => {
|
|
3247
3163
|
scrollWrapper?.scrollBy({ top: -150, behavior: 'smooth' });
|
|
@@ -3249,11 +3165,11 @@ const VerticalScrollButtons = ({ scrollWrapper, }) => {
|
|
|
3249
3165
|
const scrollBottomClickHandler = () => {
|
|
3250
3166
|
scrollWrapper?.scrollBy({ top: 150, behavior: 'smooth' });
|
|
3251
3167
|
};
|
|
3252
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [scrollPosition && scrollPosition !== 'top' && (jsxRuntime.jsx(IconButton, { onClick: scrollTopClickHandler, icon: "caret-up", className: "str-video__speaker-layout__participants-bar--button-top" })), scrollPosition && scrollPosition !== 'bottom' && (jsxRuntime.jsx(IconButton, { onClick: scrollBottomClickHandler, icon: "caret-down", className: "str-video__speaker-layout__participants-bar--button-bottom" }))] }));
|
|
3168
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [scrollPosition && scrollPosition !== 'top' && (jsxRuntime.jsx(IconButton, { size: "sm", variant: "secondary", onClick: scrollTopClickHandler, icon: "caret-up", "aria-label": t('callLayout.speakerLayout.scrollParticipantsUp.ariaLabel', 'Scroll participants up'), className: "str-video__speaker-layout__participants-bar--button-top" })), scrollPosition && scrollPosition !== 'bottom' && (jsxRuntime.jsx(IconButton, { size: "sm", variant: "secondary", onClick: scrollBottomClickHandler, icon: "caret-down", "aria-label": t('callLayout.speakerLayout.scrollParticipantsDown.ariaLabel', 'Scroll participants down'), className: "str-video__speaker-layout__participants-bar--button-bottom" }))] }));
|
|
3253
3169
|
};
|
|
3254
3170
|
|
|
3255
3171
|
const Pip = (props) => {
|
|
3256
|
-
const { t } =
|
|
3172
|
+
const { t } = useI18n();
|
|
3257
3173
|
const { excludeLocalParticipant = false, filterParticipants, mirrorLocalParticipantVideo = true, VideoPlaceholder, ParticipantViewUI = DefaultParticipantViewUI, } = props;
|
|
3258
3174
|
const [layoutWrapperElement, setLayoutWrapperElement] = react.useState(null);
|
|
3259
3175
|
const call = videoReactBindings.useCall();
|
|
@@ -3272,7 +3188,7 @@ const Pip = (props) => {
|
|
|
3272
3188
|
if (!call)
|
|
3273
3189
|
return null;
|
|
3274
3190
|
return (jsxRuntime.jsxs("div", { className: "str-video__pip-layout", ref: setLayoutWrapperElement, children: [screenSharingParticipant &&
|
|
3275
|
-
(screenSharingParticipant.isLocalParticipant ? (jsxRuntime.jsxs("div", { className: "str-video__pip-screen-share-local", children: [jsxRuntime.jsx(Icon, { icon: "screen-share-off" }), jsxRuntime.jsx("span", { className: "str-video__pip-screen-share-local__title", children: t('You are presenting your screen') })] })) : (jsxRuntime.jsx(ParticipantView, { participant: screenSharingParticipant, trackType: "screenShareTrack", muteAudio: true, mirror: false, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }))), participants.map((participant) => (jsxRuntime.jsx(ParticipantView, { participant: participant, muteAudio: true, mirror: mirror, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }, participant.sessionId)))] }));
|
|
3191
|
+
(screenSharingParticipant.isLocalParticipant ? (jsxRuntime.jsxs("div", { className: "str-video__pip-screen-share-local", children: [jsxRuntime.jsx(Icon, { icon: "screen-share-off" }), jsxRuntime.jsx("span", { className: "str-video__pip-screen-share-local__title", children: t('common.presentingYourScreen.text', 'You are presenting your screen') })] })) : (jsxRuntime.jsx(ParticipantView, { participant: screenSharingParticipant, trackType: "screenShareTrack", muteAudio: true, mirror: false, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }))), participants.map((participant) => (jsxRuntime.jsx(ParticipantView, { participant: participant, muteAudio: true, mirror: mirror, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }, participant.sessionId)))] }));
|
|
3276
3192
|
};
|
|
3277
3193
|
Pip.displayName = 'PipLayout.Pip';
|
|
3278
3194
|
|
|
@@ -3298,7 +3214,7 @@ const getGridDensity = (count) => {
|
|
|
3298
3214
|
* Use this when you need a more structured grid view in PIP mode.
|
|
3299
3215
|
*/
|
|
3300
3216
|
const Grid = (props) => {
|
|
3301
|
-
const { t } =
|
|
3217
|
+
const { t } = useI18n();
|
|
3302
3218
|
const { excludeLocalParticipant = false, filterParticipants, mirrorLocalParticipantVideo = true, groupSize = 9, pageArrowsVisible = true, VideoPlaceholder, ParticipantViewUI = DefaultParticipantViewUI, } = props;
|
|
3303
3219
|
const [page, setPage] = react.useState(0);
|
|
3304
3220
|
const [wrapperElement, setWrapperElement] = react.useState(null);
|
|
@@ -3324,7 +3240,7 @@ const Grid = (props) => {
|
|
|
3324
3240
|
if (!call)
|
|
3325
3241
|
return null;
|
|
3326
3242
|
return (jsxRuntime.jsxs("div", { className: "str-video__pip-layout str-video__pip-layout--grid", ref: setWrapperElement, children: [screenSharingParticipant &&
|
|
3327
|
-
(screenSharingParticipant.isLocalParticipant ? (jsxRuntime.jsxs("div", { className: "str-video__pip-screen-share-local", children: [jsxRuntime.jsx(Icon, { icon: "screen-share-off" }), jsxRuntime.jsx("span", { className: "str-video__pip-screen-share-local__title", children: t('You are presenting your screen') })] })) : (jsxRuntime.jsx(ParticipantView, { participant: screenSharingParticipant, trackType: "screenShareTrack", muteAudio: true, mirror: false, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }))), jsxRuntime.jsxs("div", { className: "str-video__pip-layout__grid-container", children: [pageArrowsVisible && page > 0 && (jsxRuntime.jsx(IconButton, { icon: "caret-left", onClick: () => setPage((currentPage) => Math.max(0, currentPage - 1)), className: "str-video__pip-layout__pagination-button str-video__pip-layout__pagination-button--left" })), selectedGroup && (jsxRuntime.jsx("div", { className: clsx('str-video__pip-layout__grid', `str-video__pip-layout__grid--${getGridDensity(selectedGroup.length)}`), children: selectedGroup.map((participant) => (jsxRuntime.jsx(ParticipantView, { participant: participant, muteAudio: true, mirror: mirror, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }, participant.sessionId))) })), pageArrowsVisible && page < pageCount - 1 && (jsxRuntime.jsx(IconButton, { icon: "caret-right", onClick: () => setPage((currentPage) => Math.min(pageCount - 1, currentPage + 1)), className: "str-video__pip-layout__pagination-button str-video__pip-layout__pagination-button--right" }))] })] }));
|
|
3243
|
+
(screenSharingParticipant.isLocalParticipant ? (jsxRuntime.jsxs("div", { className: "str-video__pip-screen-share-local", children: [jsxRuntime.jsx(Icon, { icon: "screen-share-off" }), jsxRuntime.jsx("span", { className: "str-video__pip-screen-share-local__title", children: t('common.presentingYourScreen.text', 'You are presenting your screen') })] })) : (jsxRuntime.jsx(ParticipantView, { participant: screenSharingParticipant, trackType: "screenShareTrack", muteAudio: true, mirror: false, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }))), jsxRuntime.jsxs("div", { className: "str-video__pip-layout__grid-container", children: [pageArrowsVisible && page > 0 && (jsxRuntime.jsx(IconButton, { icon: "caret-left", size: "sm", variant: "secondary", onClick: () => setPage((currentPage) => Math.max(0, currentPage - 1)), className: "str-video__pip-layout__pagination-button str-video__pip-layout__pagination-button--left" })), selectedGroup && (jsxRuntime.jsx("div", { className: clsx('str-video__pip-layout__grid', `str-video__pip-layout__grid--${getGridDensity(selectedGroup.length)}`), children: selectedGroup.map((participant) => (jsxRuntime.jsx(ParticipantView, { participant: participant, muteAudio: true, mirror: mirror, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }, participant.sessionId))) })), pageArrowsVisible && page < pageCount - 1 && (jsxRuntime.jsx(IconButton, { icon: "caret-right", size: "sm", variant: "secondary", onClick: () => setPage((currentPage) => Math.min(pageCount - 1, currentPage + 1)), className: "str-video__pip-layout__pagination-button str-video__pip-layout__pagination-button--right" }))] })] }));
|
|
3328
3244
|
};
|
|
3329
3245
|
Grid.displayName = 'PipLayout.Grid';
|
|
3330
3246
|
|
|
@@ -3411,7 +3327,7 @@ const checkCanJoinEarly = (startsAt, joinAheadTimeSeconds) => {
|
|
|
3411
3327
|
return Date.now() >= +startsAt - (joinAheadTimeSeconds ?? 0) * 1000;
|
|
3412
3328
|
};
|
|
3413
3329
|
|
|
3414
|
-
const [major, minor, patch] = ("2.0.0-beta.
|
|
3330
|
+
const [major, minor, patch] = ("2.0.0-beta.1").split('.');
|
|
3415
3331
|
videoClient.setSdkInfo({
|
|
3416
3332
|
type: videoClient.SfuModels.SdkType.REACT,
|
|
3417
3333
|
major,
|
|
@@ -3419,6 +3335,22 @@ videoClient.setSdkInfo({
|
|
|
3419
3335
|
patch,
|
|
3420
3336
|
});
|
|
3421
3337
|
|
|
3338
|
+
Object.defineProperty(exports, "asDynamicKey", {
|
|
3339
|
+
enumerable: true,
|
|
3340
|
+
get: function () { return i18n.asDynamicKey; }
|
|
3341
|
+
});
|
|
3342
|
+
Object.defineProperty(exports, "defaultDateTimeParser", {
|
|
3343
|
+
enumerable: true,
|
|
3344
|
+
get: function () { return i18n.defaultDateTimeParser; }
|
|
3345
|
+
});
|
|
3346
|
+
Object.defineProperty(exports, "getDateString", {
|
|
3347
|
+
enumerable: true,
|
|
3348
|
+
get: function () { return i18n.getDateString; }
|
|
3349
|
+
});
|
|
3350
|
+
Object.defineProperty(exports, "predefinedFormatters", {
|
|
3351
|
+
enumerable: true,
|
|
3352
|
+
get: function () { return i18n.predefinedFormatters; }
|
|
3353
|
+
});
|
|
3422
3354
|
exports.AcceptCallButton = AcceptCallButton;
|
|
3423
3355
|
exports.Audio = Audio;
|
|
3424
3356
|
exports.AudioVolumeIndicator = AudioVolumeIndicator;
|
|
@@ -3426,7 +3358,9 @@ exports.Avatar = Avatar;
|
|
|
3426
3358
|
exports.AvatarFallback = AvatarFallback;
|
|
3427
3359
|
exports.BackgroundFiltersProvider = BackgroundFiltersProvider;
|
|
3428
3360
|
exports.BackstageLayout = BackstageLayout;
|
|
3361
|
+
exports.Badge = Badge;
|
|
3429
3362
|
exports.BaseVideo = BaseVideo;
|
|
3363
|
+
exports.Button = Button;
|
|
3430
3364
|
exports.CallControls = CallControls;
|
|
3431
3365
|
exports.CallParticipantListing = CallParticipantListing;
|
|
3432
3366
|
exports.CallParticipantListingItem = CallParticipantListingItem;
|
|
@@ -3435,11 +3369,10 @@ exports.CallPreview = CallPreview;
|
|
|
3435
3369
|
exports.CallRecordingList = CallRecordingList;
|
|
3436
3370
|
exports.CallRecordingListHeader = CallRecordingListHeader;
|
|
3437
3371
|
exports.CallRecordingListItem = CallRecordingListItem;
|
|
3438
|
-
exports.CallStats = CallStats;
|
|
3439
|
-
exports.CallStatsButton = CallStatsButton;
|
|
3440
3372
|
exports.CancelCallButton = CancelCallButton;
|
|
3441
3373
|
exports.CancelCallConfirmButton = CancelCallConfirmButton;
|
|
3442
3374
|
exports.CompositeButton = CompositeButton;
|
|
3375
|
+
exports.ConnectionQualityIndicator = ConnectionQualityIndicator;
|
|
3443
3376
|
exports.DefaultAudioBlockedNotification = DefaultAudioBlockedNotification;
|
|
3444
3377
|
exports.DefaultParticipantViewUI = DefaultParticipantViewUI;
|
|
3445
3378
|
exports.DefaultReactionsMenu = DefaultReactionsMenu;
|
|
@@ -3455,6 +3388,7 @@ exports.DropDownSelectOption = DropDownSelectOption;
|
|
|
3455
3388
|
exports.EmptyCallRecordingListing = EmptyCallRecordingListing;
|
|
3456
3389
|
exports.GenericMenu = GenericMenu;
|
|
3457
3390
|
exports.GenericMenuButtonItem = GenericMenuButtonItem;
|
|
3391
|
+
exports.GenericMenuSeparator = GenericMenuSeparator;
|
|
3458
3392
|
exports.Icon = Icon;
|
|
3459
3393
|
exports.IconButton = IconButton;
|
|
3460
3394
|
exports.LivestreamLayout = LivestreamLayout;
|
|
@@ -3489,28 +3423,29 @@ exports.SpeakerLayout = SpeakerLayout;
|
|
|
3489
3423
|
exports.SpeakerTest = SpeakerTest;
|
|
3490
3424
|
exports.SpeakingWhileMutedNotification = SpeakingWhileMutedNotification;
|
|
3491
3425
|
exports.SpeechIndicator = SpeechIndicator;
|
|
3492
|
-
exports.StatCard = StatCard;
|
|
3493
3426
|
exports.StreamCall = StreamCall;
|
|
3494
3427
|
exports.StreamTheme = StreamTheme;
|
|
3495
3428
|
exports.StreamVideo = StreamVideo;
|
|
3496
|
-
exports.
|
|
3429
|
+
exports.Streami18n = Streami18n;
|
|
3497
3430
|
exports.ToggleAudioOutputButton = ToggleAudioOutputButton;
|
|
3498
3431
|
exports.ToggleAudioPreviewButton = ToggleAudioPreviewButton;
|
|
3499
3432
|
exports.ToggleAudioPublishingButton = ToggleAudioPublishingButton;
|
|
3500
3433
|
exports.ToggleVideoPreviewButton = ToggleVideoPreviewButton;
|
|
3501
3434
|
exports.ToggleVideoPublishingButton = ToggleVideoPublishingButton;
|
|
3502
3435
|
exports.Tooltip = Tooltip;
|
|
3503
|
-
exports.
|
|
3436
|
+
exports.TranslationContext = TranslationContext;
|
|
3437
|
+
exports.TranslationProvider = TranslationProvider;
|
|
3438
|
+
exports.Video = Video;
|
|
3504
3439
|
exports.VideoPreview = VideoPreview;
|
|
3505
3440
|
exports.WithTooltip = WithTooltip;
|
|
3506
3441
|
exports.applyFilter = applyFilter;
|
|
3507
3442
|
exports.defaultEmojiReactionMap = defaultEmojiReactionMap;
|
|
3508
3443
|
exports.defaultReactions = defaultReactions;
|
|
3509
|
-
exports.translations = translations;
|
|
3510
3444
|
exports.useBackgroundFilters = useBackgroundFilters;
|
|
3511
3445
|
exports.useDeviceList = useDeviceList;
|
|
3512
3446
|
exports.useFilteredParticipants = useFilteredParticipants;
|
|
3513
3447
|
exports.useHorizontalScrollPosition = useHorizontalScrollPosition;
|
|
3448
|
+
exports.useI18n = useI18n;
|
|
3514
3449
|
exports.useLoopbackRecording = useLoopbackRecording;
|
|
3515
3450
|
exports.useMenuContext = useMenuContext;
|
|
3516
3451
|
exports.useModeration = useModeration;
|
|
@@ -3518,6 +3453,7 @@ exports.useNoiseCancellation = useNoiseCancellation;
|
|
|
3518
3453
|
exports.useParticipantViewContext = useParticipantViewContext;
|
|
3519
3454
|
exports.usePersistedDevicePreferences = usePersistedDevicePreferences;
|
|
3520
3455
|
exports.useRequestPermission = useRequestPermission;
|
|
3456
|
+
exports.useStreami18n = useStreami18n;
|
|
3521
3457
|
exports.useTrackElementVisibility = useTrackElementVisibility;
|
|
3522
3458
|
exports.useVerticalScrollPosition = useVerticalScrollPosition;
|
|
3523
3459
|
Object.keys(videoClient).forEach(function (k) {
|