@stream-io/video-react-sdk 1.43.2 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -19
- 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/embedded.cjs.js
CHANGED
|
@@ -4,7 +4,9 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var videoReactBindings = require('@stream-io/video-react-bindings');
|
|
6
6
|
var videoClient = require('@stream-io/video-client');
|
|
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 };
|
|
@@ -177,7 +330,7 @@ const useRequestPermission = (permission) => {
|
|
|
177
330
|
* 2. Maps the device list to a format more suitable for rendering.
|
|
178
331
|
*/
|
|
179
332
|
function useDeviceList(devices, selectedDeviceId) {
|
|
180
|
-
const { t } =
|
|
333
|
+
const { t } = useI18n();
|
|
181
334
|
return react.useMemo(() => {
|
|
182
335
|
let selectedDeviceInfo = null;
|
|
183
336
|
let selectedIndex = null;
|
|
@@ -193,7 +346,7 @@ function useDeviceList(devices, selectedDeviceId) {
|
|
|
193
346
|
if (selectedDeviceInfo === null || selectedIndex === null) {
|
|
194
347
|
const defaultDevice = {
|
|
195
348
|
deviceId: 'default',
|
|
196
|
-
label: t('Default'),
|
|
349
|
+
label: t('common.default.label', 'Default'),
|
|
197
350
|
isSelected: true,
|
|
198
351
|
};
|
|
199
352
|
selectedDeviceInfo = defaultDevice;
|
|
@@ -333,7 +486,7 @@ const useMenuContext = () => {
|
|
|
333
486
|
};
|
|
334
487
|
const MenuPortal = ({ children, refs, }) => {
|
|
335
488
|
const [portalRoot, setPortalRoot] = react.useState(null);
|
|
336
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { ref: setPortalRoot, className: "str-video__portal" }), jsxRuntime.jsx(react$
|
|
489
|
+
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 }) }) })] }));
|
|
337
490
|
};
|
|
338
491
|
const MenuToggle = ({ ToggleButton, placement = 'top-start', strategy = 'absolute', offset, visualType = MenuVisualType.MENU, children, onToggle, }) => {
|
|
339
492
|
const [menuShown, setMenuShown] = react.useState(false);
|
|
@@ -395,6 +548,7 @@ const GenericMenu = ({ children, onItemClick, }) => {
|
|
|
395
548
|
const GenericMenuButtonItem = ({ children, ...rest }) => {
|
|
396
549
|
return (jsxRuntime.jsx("li", { className: "str-video__generic-menu--item", children: jsxRuntime.jsx("button", { ...rest, children: children }) }));
|
|
397
550
|
};
|
|
551
|
+
const GenericMenuSeparator = () => (jsxRuntime.jsx("li", { className: "str-video__generic-menu--separator", role: "separator" }));
|
|
398
552
|
|
|
399
553
|
const Icon = ({ className, icon }) => (jsxRuntime.jsx("span", { className: clsx('str-video__icon', icon && `str-video__icon--${icon}`, className) }));
|
|
400
554
|
|
|
@@ -423,7 +577,7 @@ const ParticipantActionsContextMenu = () => {
|
|
|
423
577
|
const [fullscreenModeOn, setFullscreenModeOn] = react.useState(!!document.fullscreenElement);
|
|
424
578
|
const call = videoReactBindings.useCall();
|
|
425
579
|
const isPiP = usePictureInPictureState(videoElement ?? undefined);
|
|
426
|
-
const { t } =
|
|
580
|
+
const { t } = useI18n();
|
|
427
581
|
const { pin, sessionId, userId } = participant;
|
|
428
582
|
const hasAudioTrack = videoClient.hasAudio(participant);
|
|
429
583
|
const hasVideoTrack = videoClient.hasVideo(participant);
|
|
@@ -495,12 +649,14 @@ const ParticipantActionsContextMenu = () => {
|
|
|
495
649
|
return document.exitPictureInPicture().catch(console.error);
|
|
496
650
|
};
|
|
497
651
|
const { close } = useMenuContext() || {};
|
|
498
|
-
return (jsxRuntime.jsxs(GenericMenu, { onItemClick: close, children: [jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: toggleParticipantPin, disabled: pin && !pin.isLocalPin, children: [jsxRuntime.jsx(Icon, { icon: "pin" }), pin
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
652
|
+
return (jsxRuntime.jsxs(GenericMenu, { onItemClick: close, children: [jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: toggleParticipantPin, disabled: pin && !pin.isLocalPin, children: [jsxRuntime.jsx(Icon, { icon: "pin" }), pin
|
|
653
|
+
? t('participantView.unpin.label', 'Unpin')
|
|
654
|
+
: 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 &&
|
|
655
|
+
typeof participantViewElement.requestFullscreen !== 'undefined' && (jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: toggleFullscreenMode, children: [jsxRuntime.jsx(Icon, { icon: "fullscreen" }), fullscreenModeOn
|
|
656
|
+
? t('participantView.actionsMenu.leaveFullscreen.label', 'Leave fullscreen')
|
|
657
|
+
: t('participantView.actionsMenu.enterFullscreen.label', 'Enter fullscreen')] })), videoElement && document.pictureInPictureEnabled && (jsxRuntime.jsxs(GenericMenuButtonItem, { onClick: togglePictureInPicture, children: [jsxRuntime.jsx(Icon, { icon: "pip" }), isPiP
|
|
658
|
+
? t('participantView.actionsMenu.leavePip.label', 'Leave picture-in-picture')
|
|
659
|
+
: 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') })] })] }));
|
|
504
660
|
};
|
|
505
661
|
|
|
506
662
|
const isComponentType = (elementOrComponent) => {
|
|
@@ -565,34 +721,39 @@ const BaseVideo = react.forwardRef(function BaseVideoRender({ stream, ...rest },
|
|
|
565
721
|
} }));
|
|
566
722
|
});
|
|
567
723
|
|
|
568
|
-
const
|
|
724
|
+
const variantClasses = ({ size = 'md', showOutline }) => [
|
|
725
|
+
`str-video__avatar--size-${size}`,
|
|
726
|
+
showOutline && 'str-video__avatar--outlined',
|
|
727
|
+
];
|
|
728
|
+
const Avatar = ({ imageSrc, name, style, className, size = 'md', showOutline, ...rest }) => {
|
|
569
729
|
const [error, setError] = react.useState(false);
|
|
730
|
+
if (!imageSrc || error) {
|
|
731
|
+
return name ? (jsxRuntime.jsx(AvatarFallback, { className: className, style: style, names: name.split(/\s+/).filter(Boolean), size: size, showOutline: showOutline })) : null;
|
|
732
|
+
}
|
|
733
|
+
return (jsxRuntime.jsx("img", { onError: () => setError(true), alt: "avatar", className: clsx('str-video__avatar', variantClasses({ size, showOutline }), className), src: imageSrc, style: style, ...rest }));
|
|
734
|
+
};
|
|
735
|
+
const AvatarFallback = ({ className, names, style, size = 'md', showOutline, }) => {
|
|
736
|
+
const isCompact = size === 'xs' || size === 'sm';
|
|
737
|
+
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]] }) }));
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
const BaseVideoPlaceholder = react.forwardRef(function DefaultVideoPlaceholder({ participant, style, children }, ref) {
|
|
570
741
|
const name = participant.name || participant.userId;
|
|
571
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__video-placeholder", style: style, ref: ref, children: [(
|
|
572
|
-
(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 }))] }));
|
|
742
|
+
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 }))] }));
|
|
573
743
|
});
|
|
574
|
-
const InitialsFallback = (props) => {
|
|
575
|
-
const { name } = props;
|
|
576
|
-
const initials = name
|
|
577
|
-
.split(' ')
|
|
578
|
-
.slice(0, 2)
|
|
579
|
-
.map((n) => n[0])
|
|
580
|
-
.join('');
|
|
581
|
-
return (jsxRuntime.jsx("div", { className: "str-video__video-placeholder__initials-fallback", children: initials }));
|
|
582
|
-
};
|
|
583
744
|
|
|
584
745
|
const DefaultVideoPlaceholder = react.forwardRef(function DefaultVideoPlaceholderRender(props, ref) {
|
|
585
|
-
const { t } =
|
|
586
|
-
return (jsxRuntime.jsx(BaseVideoPlaceholder, { ref: ref, ...props, children: t('Video is disabled') }));
|
|
746
|
+
const { t } = useI18n();
|
|
747
|
+
return (jsxRuntime.jsx(BaseVideoPlaceholder, { ref: ref, ...props, children: t('common.videoDisabled.text', 'Video is disabled') }));
|
|
587
748
|
});
|
|
588
749
|
|
|
589
750
|
const DefaultPictureInPicturePlaceholder = react.forwardRef(function DefaultPictureInPicturePlaceholderRender(props, ref) {
|
|
590
|
-
const { t } =
|
|
591
|
-
return (jsxRuntime.jsx(BaseVideoPlaceholder, { ref: ref, ...props, children: t('Video is playing in a popup') }));
|
|
751
|
+
const { t } = useI18n();
|
|
752
|
+
return (jsxRuntime.jsx(BaseVideoPlaceholder, { ref: ref, ...props, children: t('videoPlaceholder.videoPlayingInPopup.text', 'Video is playing in a popup') }));
|
|
592
753
|
});
|
|
593
754
|
|
|
594
755
|
const ABSOLUTE_POSITION_STYLE = { position: 'absolute' };
|
|
595
|
-
const Video
|
|
756
|
+
const Video = ({ enabled = true, mirror, trackType, participant, className, VideoPlaceholder = DefaultVideoPlaceholder, PictureInPicturePlaceholder = DefaultPictureInPicturePlaceholder, refs, ...rest }) => {
|
|
596
757
|
const { sessionId, videoStream, screenShareStream, viewportVisibilityState, isLocalParticipant, userId, } = participant;
|
|
597
758
|
const call = videoReactBindings.useCall();
|
|
598
759
|
const [videoElement, setVideoElement] = react.useState(null);
|
|
@@ -666,7 +827,7 @@ const Video$1 = ({ enabled = true, mirror, trackType, participant, className, Vi
|
|
|
666
827
|
refs?.setVideoElement?.(element);
|
|
667
828
|
} })), 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 }))] }));
|
|
668
829
|
};
|
|
669
|
-
Video
|
|
830
|
+
Video.displayName = 'Video';
|
|
670
831
|
|
|
671
832
|
const useTrackElementVisibility = ({ trackedElement, sessionId, trackType, }) => {
|
|
672
833
|
const call = videoReactBindings.useCall();
|
|
@@ -677,14 +838,6 @@ const useTrackElementVisibility = ({ trackedElement, sessionId, trackType, }) =>
|
|
|
677
838
|
}, [trackedElement, call, sessionId, trackType]);
|
|
678
839
|
};
|
|
679
840
|
|
|
680
|
-
const Avatar = ({ imageSrc, name, style, className, ...rest }) => {
|
|
681
|
-
const [error, setError] = react.useState(false);
|
|
682
|
-
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 }))] }));
|
|
683
|
-
};
|
|
684
|
-
const AvatarFallback = ({ className, names, style, }) => {
|
|
685
|
-
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]] }) }));
|
|
686
|
-
};
|
|
687
|
-
|
|
688
841
|
const BackgroundFiltersProviderImpl = react.lazy(() => Promise.resolve().then(function () { return require('./embedded-BackgroundFilters-DMStbSEg.cjs.js'); }).then((m) => ({
|
|
689
842
|
default: m.BackgroundFiltersProvider,
|
|
690
843
|
})));
|
|
@@ -713,43 +866,44 @@ const BackgroundFiltersProvider = (props) => {
|
|
|
713
866
|
return (jsxRuntime.jsx(react.Suspense, { fallback: SuspenseFallback, children: jsxRuntime.jsx(BackgroundFiltersProviderImpl, { ...filterProps, ContextProvider: BackgroundFiltersContext }) }));
|
|
714
867
|
};
|
|
715
868
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
869
|
+
/**
|
|
870
|
+
* A compact badge for counts, notifications and error markers.
|
|
871
|
+
*
|
|
872
|
+
* Without `icon` it is a pill that grows with its content; with `icon` it is a
|
|
873
|
+
* circle of the size given by `size`.
|
|
874
|
+
*
|
|
875
|
+
* The badge carries no positioning of its own — whatever it annotates places
|
|
876
|
+
* it. For the call controls, rendering a badge among `CompositeButton`'s
|
|
877
|
+
* children anchors it to the top-right corner of the button.
|
|
878
|
+
*/
|
|
879
|
+
const Badge = react.forwardRef(function BadgeRender({ variant = 'default', size = 'sm', icon, className, children, ...rest }, ref) {
|
|
880
|
+
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 }));
|
|
725
881
|
});
|
|
726
882
|
|
|
727
|
-
const
|
|
728
|
-
return (jsxRuntime.
|
|
729
|
-
'str-video__composite-button--caption': caption,
|
|
730
|
-
'str-video__composite-button--menu': Menu,
|
|
731
|
-
}), title: title, ref: ref, children: [jsxRuntime.jsxs("div", { className: clsx('str-video__composite-button__button-group', {
|
|
732
|
-
'str-video__composite-button__button-group--active': active,
|
|
733
|
-
'str-video__composite-button__button-group--active-primary': active && variant === 'primary',
|
|
734
|
-
'str-video__composite-button__button-group--active-secondary': active && variant === 'secondary',
|
|
735
|
-
'str-video__composite-button__button-group--disabled': disabled,
|
|
736
|
-
}), children: [jsxRuntime.jsx("button", { type: "button", className: "str-video__composite-button__button", onClick: (e) => {
|
|
737
|
-
e.preventDefault();
|
|
738
|
-
onClick?.(e);
|
|
739
|
-
}, 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 }))] }));
|
|
883
|
+
const Button = react.forwardRef(function ButtonRender({ variant = 'primary', appearance = 'solid', size = 'md', active, className, type = 'button', children, ...rest }, ref) {
|
|
884
|
+
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 }));
|
|
740
885
|
});
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
}), icon: menuShown ? 'caret-down' : 'caret-up', ref: ref }));
|
|
886
|
+
|
|
887
|
+
const IconButton = react.forwardRef(function IconButtonRender({ icon, className, ...props }, ref) {
|
|
888
|
+
return (jsxRuntime.jsx(Button, { ref: ref, className: clsx('str-video__button--icon-only', className), ...props, children: jsxRuntime.jsx(Icon, { icon: icon }) }));
|
|
745
889
|
});
|
|
746
890
|
|
|
747
|
-
const
|
|
748
|
-
return (jsxRuntime.
|
|
749
|
-
};
|
|
891
|
+
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) {
|
|
892
|
+
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 &&
|
|
893
|
+
(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 }))] }));
|
|
894
|
+
});
|
|
895
|
+
const CompositeCaret = react.forwardRef(function CompositeCaretRender({ menuShown, disabled }, ref) {
|
|
896
|
+
const { t } = useI18n();
|
|
897
|
+
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 }));
|
|
898
|
+
});
|
|
750
899
|
|
|
900
|
+
const ICON_BY_STATE = {
|
|
901
|
+
success: 'checkmark',
|
|
902
|
+
error: 'exclamation-circle-fill',
|
|
903
|
+
loading: 'loading',
|
|
904
|
+
};
|
|
751
905
|
const Notification = (props) => {
|
|
752
|
-
const { isVisible, message, children, visibilityTimeout, resetIsVisible, placement = 'top', className,
|
|
906
|
+
const { isVisible, message, children, visibilityTimeout, resetIsVisible, placement = 'top', className, state, close, } = props;
|
|
753
907
|
const { refs, x, y, strategy } = useFloatingUIPreset({
|
|
754
908
|
placement,
|
|
755
909
|
strategy: 'absolute',
|
|
@@ -762,12 +916,13 @@ const Notification = (props) => {
|
|
|
762
916
|
}, visibilityTimeout);
|
|
763
917
|
return () => clearTimeout(timeout);
|
|
764
918
|
}, [isVisible, resetIsVisible, visibilityTimeout]);
|
|
765
|
-
|
|
919
|
+
const icon = state && `str-video__icon str-video__icon--${ICON_BY_STATE[state]}`;
|
|
920
|
+
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: {
|
|
766
921
|
position: strategy,
|
|
767
922
|
top: y ?? 0,
|
|
768
923
|
left: x ?? 0,
|
|
769
924
|
overflowY: 'auto',
|
|
770
|
-
}, children: [
|
|
925
|
+
}, 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] }));
|
|
771
926
|
};
|
|
772
927
|
|
|
773
928
|
const PermissionNotification = (props) => {
|
|
@@ -790,22 +945,23 @@ const PermissionNotification = (props) => {
|
|
|
790
945
|
}, [hasPermission]);
|
|
791
946
|
const resetIsVisible = react.useCallback(() => setShowNotification(undefined), []);
|
|
792
947
|
if (isAwaitingApproval) {
|
|
793
|
-
return (jsxRuntime.jsx(Notification, { isVisible: isAwaitingApproval && !hasPermission, message: messageAwaitingApproval, children: children }));
|
|
948
|
+
return (jsxRuntime.jsx(Notification, { state: "loading", isVisible: isAwaitingApproval && !hasPermission, message: messageAwaitingApproval, children: children }));
|
|
794
949
|
}
|
|
795
|
-
return (jsxRuntime.jsx(Notification, { isVisible: !!showNotification, visibilityTimeout: visibilityTimeout, resetIsVisible: resetIsVisible, message: showNotification === 'granted' ? messageApproved : messageRevoked, children: children }));
|
|
950
|
+
return (jsxRuntime.jsx(Notification, { state: showNotification === 'granted' ? 'success' : 'error', isVisible: !!showNotification, visibilityTimeout: visibilityTimeout, resetIsVisible: resetIsVisible, message: showNotification === 'granted' ? messageApproved : messageRevoked, children: children }));
|
|
796
951
|
};
|
|
797
952
|
|
|
798
953
|
const SpeakingWhileMutedNotification = ({ children, text, placement, }) => {
|
|
799
954
|
const { useMicrophoneState } = videoReactBindings.useCallStateHooks();
|
|
800
955
|
const { isSpeakingWhileMuted } = useMicrophoneState();
|
|
801
|
-
const { t } =
|
|
802
|
-
const message = text ??
|
|
956
|
+
const { t } = useI18n();
|
|
957
|
+
const message = text ??
|
|
958
|
+
t('notification.speakingWhileMuted.text', 'You are muted. Unmute to speak.');
|
|
803
959
|
return (jsxRuntime.jsx(Notification, { message: message, isVisible: isSpeakingWhileMuted, placement: placement || 'top-start', children: children }));
|
|
804
960
|
};
|
|
805
961
|
|
|
806
962
|
const MicCaptureErrorNotification = ({ children, text, placement, }) => {
|
|
807
963
|
const call = videoReactBindings.useCall();
|
|
808
|
-
const { t } =
|
|
964
|
+
const { t } = useI18n();
|
|
809
965
|
const [isVisible, setIsVisible] = react.useState(false);
|
|
810
966
|
react.useEffect(() => {
|
|
811
967
|
if (!call)
|
|
@@ -815,8 +971,8 @@ const MicCaptureErrorNotification = ({ children, text, placement, }) => {
|
|
|
815
971
|
});
|
|
816
972
|
}, [call]);
|
|
817
973
|
const message = text ??
|
|
818
|
-
t('Your microphone is not capturing audio. Please check your setup.');
|
|
819
|
-
return (jsxRuntime.jsx(Notification, { message: message, isVisible: isVisible, placement: placement, close: () => setIsVisible(false), children: children }));
|
|
974
|
+
t('notification.micCaptureError.text', 'Your microphone is not capturing audio. Please check your setup.');
|
|
975
|
+
return (jsxRuntime.jsx(Notification, { message: message, state: "error", isVisible: isVisible, placement: placement, close: () => setIsVisible(false), children: children }));
|
|
820
976
|
};
|
|
821
977
|
|
|
822
978
|
const LoadingIndicator = ({ className, type = 'spinner', text, tooltip, }) => {
|
|
@@ -824,22 +980,20 @@ const LoadingIndicator = ({ className, type = 'spinner', text, tooltip, }) => {
|
|
|
824
980
|
};
|
|
825
981
|
|
|
826
982
|
const Tooltip = ({ children, referenceElement, tooltipClassName, tooltipPlacement = 'top', visible = false, }) => {
|
|
827
|
-
const
|
|
828
|
-
const { refs, x, y, strategy, context } = useFloatingUIPreset({
|
|
983
|
+
const { refs, x, y, strategy } = useFloatingUIPreset({
|
|
829
984
|
placement: tooltipPlacement,
|
|
830
985
|
strategy: 'absolute',
|
|
831
|
-
middleware: [react$1.arrow({ element: arrowRef })],
|
|
832
986
|
});
|
|
833
987
|
react.useEffect(() => {
|
|
834
988
|
refs.setReference(referenceElement);
|
|
835
989
|
}, [referenceElement, refs]);
|
|
836
990
|
if (!visible)
|
|
837
991
|
return null;
|
|
838
|
-
return (jsxRuntime.
|
|
992
|
+
return (jsxRuntime.jsx("div", { className: clsx('str-video__tooltip', tooltipClassName), ref: refs.setFloating, style: {
|
|
839
993
|
position: strategy,
|
|
840
994
|
top: y ?? 0,
|
|
841
995
|
left: x ?? 0,
|
|
842
|
-
}, children:
|
|
996
|
+
}, children: children }));
|
|
843
997
|
};
|
|
844
998
|
|
|
845
999
|
const useEnterLeaveHandlers = ({ onMouseEnter, onMouseLeave, } = {}) => {
|
|
@@ -891,18 +1045,18 @@ function isNotAllowedError(error) {
|
|
|
891
1045
|
}
|
|
892
1046
|
|
|
893
1047
|
const RecordEndConfirmation = (props) => {
|
|
894
|
-
const { t } =
|
|
1048
|
+
const { t } = useI18n();
|
|
895
1049
|
const { toggleCallRecording, isAwaitingResponse } = videoReactBindings.useToggleCallRecording();
|
|
896
1050
|
const { close } = useMenuContext();
|
|
897
1051
|
const handleClick = createCallControlHandler(props, toggleCallRecording);
|
|
898
|
-
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') })
|
|
1052
|
+
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') })] })] }));
|
|
899
1053
|
};
|
|
900
1054
|
const ToggleEndRecordingMenuButton = react.forwardRef(function ToggleEndRecordingMenuButtonRender(props, ref) {
|
|
901
|
-
return (jsxRuntime.jsx(CompositeButton, { ref: ref, active: true, variant: "
|
|
1055
|
+
return (jsxRuntime.jsx(CompositeButton, { ref: ref, active: true, variant: "destructive", "data-testid": "recording-stop-button", children: jsxRuntime.jsx(Icon, { icon: "recording-off" }) }));
|
|
902
1056
|
});
|
|
903
1057
|
const RecordCallConfirmationButton = (props) => {
|
|
904
1058
|
const { caption } = props;
|
|
905
|
-
const { t } =
|
|
1059
|
+
const { t } = useI18n();
|
|
906
1060
|
const { toggleCallRecording, isAwaitingResponse, isCallRecordingInProgress } = videoReactBindings.useToggleCallRecording();
|
|
907
1061
|
const handleClick = createCallControlHandler(props, toggleCallRecording);
|
|
908
1062
|
if (isCallRecordingInProgress) {
|
|
@@ -912,12 +1066,13 @@ const RecordCallConfirmationButton = (props) => {
|
|
|
912
1066
|
], children: jsxRuntime.jsx(MenuToggle, { ToggleButton: ToggleEndRecordingMenuButton, visualType: MenuVisualType.PORTAL, children: jsxRuntime.jsx(RecordEndConfirmation, { onError: props.onError }) }) }));
|
|
913
1067
|
}
|
|
914
1068
|
const title = isAwaitingResponse
|
|
915
|
-
? t('Waiting for recording to start...')
|
|
916
|
-
: (caption ??
|
|
1069
|
+
? t('callControls.recordCallButton.waitingRecordingStart.title', 'Waiting for recording to start...')
|
|
1070
|
+
: (caption ??
|
|
1071
|
+
t('callControls.recordCallButton.recordCall.title', 'Record call'));
|
|
917
1072
|
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [
|
|
918
1073
|
videoClient.OwnCapability.START_RECORD_CALL,
|
|
919
1074
|
videoClient.OwnCapability.STOP_RECORD_CALL,
|
|
920
|
-
], children: jsxRuntime.jsx(WithTooltip, { title: title, children: jsxRuntime.jsx(CompositeButton, { active: isCallRecordingInProgress, caption: caption, variant:
|
|
1075
|
+
], 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" })) }) }) }));
|
|
921
1076
|
};
|
|
922
1077
|
|
|
923
1078
|
const defaultEmojiReactionMap = {
|
|
@@ -977,8 +1132,8 @@ const ReactionsButton = ({ reactions = defaultReactions, }) => {
|
|
|
977
1132
|
return (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx(MenuToggle, { placement: "top", ToggleButton: ToggleReactionsMenuButton, visualType: MenuVisualType.MENU, children: jsxRuntime.jsx(DefaultReactionsMenu, { reactions: reactions }) }) }));
|
|
978
1133
|
};
|
|
979
1134
|
const ToggleReactionsMenuButton = react.forwardRef(function ToggleReactionsMenuButtonRender({ menuShown }, ref) {
|
|
980
|
-
const { t } =
|
|
981
|
-
return (jsxRuntime.jsx(WithTooltip, { title: t('Reactions'), tooltipDisabled: menuShown, children: jsxRuntime.jsx(CompositeButton, { ref: ref, active: menuShown,
|
|
1135
|
+
const { t } = useI18n();
|
|
1136
|
+
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" }) }) }));
|
|
982
1137
|
});
|
|
983
1138
|
const DefaultReactionsMenu = ({ reactions, layout = 'horizontal', }) => {
|
|
984
1139
|
const call = videoReactBindings.useCall();
|
|
@@ -993,7 +1148,7 @@ const DefaultReactionsMenu = ({ reactions, layout = 'horizontal', }) => {
|
|
|
993
1148
|
};
|
|
994
1149
|
|
|
995
1150
|
const ScreenShareButton = (props) => {
|
|
996
|
-
const { t } =
|
|
1151
|
+
const { t } = useI18n();
|
|
997
1152
|
const { caption, optimisticUpdates } = props;
|
|
998
1153
|
const { useHasOngoingScreenShare, useScreenShareState, useCallSettings } = videoReactBindings.useCallStateHooks();
|
|
999
1154
|
const isSomeoneScreenSharing = useHasOngoingScreenShare();
|
|
@@ -1015,7 +1170,10 @@ const ScreenShareButton = (props) => {
|
|
|
1015
1170
|
await screenShare.toggle();
|
|
1016
1171
|
}
|
|
1017
1172
|
});
|
|
1018
|
-
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 ??
|
|
1173
|
+
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 ??
|
|
1174
|
+
t('callControls.screenShareButton.shareScreen.title', 'Share screen'), children: jsxRuntime.jsx(CompositeButton, { active: isSomeoneScreenSharing || amIScreenSharing, caption: caption, variant: isSomeoneScreenSharing || amIScreenSharing
|
|
1175
|
+
? 'primary'
|
|
1176
|
+
: 'secondary', "data-testid": isSomeoneScreenSharing
|
|
1019
1177
|
? 'screen-share-stop-button'
|
|
1020
1178
|
: 'screen-share-start-button', disabled: disableScreenShareButton, onClick: handleClick, children: jsxRuntime.jsx(Icon, { icon: isSomeoneScreenSharing ? 'screen-share-on' : 'screen-share-off' }) }) }) }) }));
|
|
1021
1179
|
};
|
|
@@ -1071,7 +1229,7 @@ const DeviceLevelIndicator = ({ deviceId }) => {
|
|
|
1071
1229
|
const DeviceAudioPreviewItem = ({ device, onSelect, }) => {
|
|
1072
1230
|
if (device.deviceId === 'default')
|
|
1073
1231
|
return null;
|
|
1074
|
-
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 })] }));
|
|
1232
|
+
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 })] }));
|
|
1075
1233
|
};
|
|
1076
1234
|
|
|
1077
1235
|
const SelectContext = react.createContext({});
|
|
@@ -1081,12 +1239,12 @@ const Select = (props) => {
|
|
|
1081
1239
|
const [activeIndex, setActiveIndex] = react.useState(null);
|
|
1082
1240
|
const [selectedIndex, setSelectedIndex] = react.useState(defaultSelectedIndex);
|
|
1083
1241
|
const [selectedLabel, setSelectedLabel] = react.useState(defaultSelectedLabel);
|
|
1084
|
-
const { refs, context } = react$
|
|
1242
|
+
const { refs, context } = react$2.useFloating({
|
|
1085
1243
|
placement: 'bottom-start',
|
|
1086
1244
|
open: isOpen,
|
|
1087
1245
|
onOpenChange: setIsOpen,
|
|
1088
|
-
whileElementsMounted: react$
|
|
1089
|
-
middleware: [react$
|
|
1246
|
+
whileElementsMounted: react$2.autoUpdate,
|
|
1247
|
+
middleware: [react$2.flip()],
|
|
1090
1248
|
});
|
|
1091
1249
|
const elementsRef = react.useRef([]);
|
|
1092
1250
|
const labelsRef = react.useRef([]);
|
|
@@ -1106,34 +1264,34 @@ const Select = (props) => {
|
|
|
1106
1264
|
handleSelect(index);
|
|
1107
1265
|
}
|
|
1108
1266
|
};
|
|
1109
|
-
const listNav = react$
|
|
1267
|
+
const listNav = react$2.useListNavigation(context, {
|
|
1110
1268
|
listRef: elementsRef,
|
|
1111
1269
|
activeIndex,
|
|
1112
1270
|
selectedIndex,
|
|
1113
1271
|
onNavigate: setActiveIndex,
|
|
1114
1272
|
});
|
|
1115
|
-
const typeahead = react$
|
|
1273
|
+
const typeahead = react$2.useTypeahead(context, {
|
|
1116
1274
|
listRef: labelsRef,
|
|
1117
1275
|
activeIndex,
|
|
1118
1276
|
selectedIndex,
|
|
1119
1277
|
onMatch: handleTypeaheadMatch,
|
|
1120
1278
|
});
|
|
1121
|
-
const click = react$
|
|
1122
|
-
const dismiss = react$
|
|
1123
|
-
const role = react$
|
|
1124
|
-
const { getReferenceProps, getFloatingProps, getItemProps } = react$
|
|
1279
|
+
const click = react$2.useClick(context);
|
|
1280
|
+
const dismiss = react$2.useDismiss(context);
|
|
1281
|
+
const role = react$2.useRole(context, { role: 'listbox' });
|
|
1282
|
+
const { getReferenceProps, getFloatingProps, getItemProps } = react$2.useInteractions([listNav, typeahead, click, dismiss, role]);
|
|
1125
1283
|
const selectContext = react.useMemo(() => ({
|
|
1126
1284
|
activeIndex,
|
|
1127
1285
|
selectedIndex,
|
|
1128
1286
|
getItemProps,
|
|
1129
1287
|
handleSelect,
|
|
1130
1288
|
}), [activeIndex, selectedIndex, getItemProps, handleSelect]);
|
|
1131
|
-
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$
|
|
1289
|
+
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 }) }) })) })] }));
|
|
1132
1290
|
};
|
|
1133
1291
|
const DropDownSelectOption = (props) => {
|
|
1134
1292
|
const { selected, label, icon } = props;
|
|
1135
1293
|
const { getItemProps, handleSelect } = react.useContext(SelectContext);
|
|
1136
|
-
const { ref, index } = react$
|
|
1294
|
+
const { ref, index } = react$2.useListItem();
|
|
1137
1295
|
return (jsxRuntime.jsxs("div", { className: clsx('str-video__dropdown-option', {
|
|
1138
1296
|
'str-video__dropdown-option--selected': selected,
|
|
1139
1297
|
}), ref: ref, ...getItemProps({
|
|
@@ -1149,7 +1307,7 @@ const DeviceSelectorOption = ({ disabled, id, label, onChange, name, selected, d
|
|
|
1149
1307
|
return (jsxRuntime.jsxs("label", { className: clsx('str-video__device-settings__option', {
|
|
1150
1308
|
'str-video__device-settings__option--selected': selected,
|
|
1151
1309
|
'str-video__device-settings__option--disabled': disabled,
|
|
1152
|
-
}), htmlFor: id, children: [jsxRuntime.jsx("input", { type: "radio", name: name, onChange: onChange, value: value, id: id, checked: selected, defaultChecked: defaultChecked, disabled: disabled }), label] }));
|
|
1310
|
+
}), 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 })] }));
|
|
1153
1311
|
};
|
|
1154
1312
|
const DeviceSelectorList = (props) => {
|
|
1155
1313
|
const { devices = [], selectedDeviceId, title, type, onChange, children, } = props;
|
|
@@ -1209,8 +1367,8 @@ const SpeakerTest = (props) => {
|
|
|
1209
1367
|
const { selectedDevice } = useSpeakerState();
|
|
1210
1368
|
const audioElementRef = react.useRef(null);
|
|
1211
1369
|
const [isPlaying, setIsPlaying] = react.useState(false);
|
|
1212
|
-
const { t } =
|
|
1213
|
-
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"
|
|
1370
|
+
const { t } = useI18n();
|
|
1371
|
+
const { audioUrl = `https://unpkg.com/${"@stream-io/video-react-sdk"}@${"2.0.0-beta.1"}/assets/piano.mp3`, } = props;
|
|
1214
1372
|
// Update audio output device when selection changes
|
|
1215
1373
|
react.useEffect(() => {
|
|
1216
1374
|
const audio = audioElementRef.current;
|
|
@@ -1245,7 +1403,9 @@ const SpeakerTest = (props) => {
|
|
|
1245
1403
|
}
|
|
1246
1404
|
}, [isPlaying, audioUrl]);
|
|
1247
1405
|
const handleAudioEnded = react.useCallback(() => setIsPlaying(false), []);
|
|
1248
|
-
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
|
|
1406
|
+
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
|
|
1407
|
+
? t('deviceSettings.speakerTest.stopTest.label', 'Stop test')
|
|
1408
|
+
: t('deviceSettings.speakerTest.testSpeaker.label', 'Test speaker')] }) })] }));
|
|
1249
1409
|
};
|
|
1250
1410
|
|
|
1251
1411
|
const DeviceSelectorAudioInput = ({ title, visualType, volumeIndicatorVisible = true, }) => {
|
|
@@ -1253,7 +1413,7 @@ const DeviceSelectorAudioInput = ({ title, visualType, volumeIndicatorVisible =
|
|
|
1253
1413
|
const { microphone, selectedDevice, devices } = useMicrophoneState();
|
|
1254
1414
|
return (jsxRuntime.jsx(DeviceSelector, { devices: devices || [], selectedDeviceId: selectedDevice, type: "audioinput", onChange: async (deviceId) => {
|
|
1255
1415
|
await microphone.select(deviceId);
|
|
1256
|
-
}, title: title, visualType: visualType, icon: "mic", PreviewItem: DeviceAudioPreviewItem, children: volumeIndicatorVisible && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("hr", { className: "str-video__device-settings__separator" })
|
|
1416
|
+
}, 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" })] })) }));
|
|
1257
1417
|
};
|
|
1258
1418
|
const DeviceSelectorAudioOutput = ({ title, visualType, speakerTestVisible = true, speakerTestAudioUrl, }) => {
|
|
1259
1419
|
const { useSpeakerState } = videoReactBindings.useCallStateHooks();
|
|
@@ -1262,7 +1422,7 @@ const DeviceSelectorAudioOutput = ({ title, visualType, speakerTestVisible = tru
|
|
|
1262
1422
|
return null;
|
|
1263
1423
|
return (jsxRuntime.jsx(DeviceSelector, { devices: devices, type: "audiooutput", selectedDeviceId: selectedDevice, onChange: (deviceId) => {
|
|
1264
1424
|
speaker.select(deviceId);
|
|
1265
|
-
}, title: title, visualType: visualType, icon: "speaker", children: speakerTestVisible &&
|
|
1425
|
+
}, title: title, visualType: visualType, icon: "speaker", children: speakerTestVisible && jsxRuntime.jsx(SpeakerTest, { audioUrl: speakerTestAudioUrl }) }));
|
|
1266
1426
|
};
|
|
1267
1427
|
|
|
1268
1428
|
const DeviceVideoPreview = ({ deviceId }) => {
|
|
@@ -1310,34 +1470,37 @@ const DeviceSelectorVideo = ({ title, visualType, }) => {
|
|
|
1310
1470
|
};
|
|
1311
1471
|
|
|
1312
1472
|
react.forwardRef(function ToggleDeviceSettingsMenuButtonRender({ menuShown }, ref) {
|
|
1313
|
-
const { t } =
|
|
1314
|
-
return (jsxRuntime.jsx(IconButton, { className: clsx('str-video__device-settings__button', {
|
|
1473
|
+
const { t } = useI18n();
|
|
1474
|
+
return (jsxRuntime.jsx(IconButton, { active: menuShown, size: "sm", variant: "secondary", className: clsx('str-video__device-settings__button', {
|
|
1315
1475
|
'str-video__device-settings__button--active': menuShown,
|
|
1316
|
-
}), title: t('Toggle device menu'), icon: "device-settings", ref: ref }));
|
|
1476
|
+
}), title: t('deviceSettings.toggleDeviceMenu.title', 'Toggle device menu'), icon: "device-settings", ref: ref }));
|
|
1317
1477
|
});
|
|
1318
1478
|
|
|
1319
1479
|
const ToggleAudioPreviewButton = (props) => {
|
|
1320
1480
|
const { caption, Menu = DeviceSelectorAudioInput, menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1321
|
-
const { t } =
|
|
1481
|
+
const { t } = useI18n();
|
|
1322
1482
|
const { useMicrophoneState, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
1323
1483
|
const { microphone, hasBrowserPermission, isPromptingPermission, optionsAwareIsMute, isTogglePending, } = useMicrophoneState({ optimisticUpdates });
|
|
1324
1484
|
const localParticipant = useLocalParticipant();
|
|
1325
1485
|
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(videoClient.SfuModels.TrackType.AUDIO);
|
|
1326
1486
|
const [tooltipDisabled, setTooltipDisabled] = react.useState(false);
|
|
1327
1487
|
const handleClick = createCallControlHandler(props, () => microphone.toggle());
|
|
1328
|
-
return (jsxRuntime.jsx(WithTooltip, { title:
|
|
1329
|
-
? t('
|
|
1330
|
-
:
|
|
1331
|
-
? t('
|
|
1332
|
-
:
|
|
1488
|
+
return (jsxRuntime.jsx(WithTooltip, { title: isPromptingPermission
|
|
1489
|
+
? t('common.waitingForPermission.title', 'Waiting for permission')
|
|
1490
|
+
: !hasBrowserPermission
|
|
1491
|
+
? t('callControls.toggleAudioButton.checkBrowserAudioPermissions.title', 'Check your browser audio permissions')
|
|
1492
|
+
: isSystemMuted
|
|
1493
|
+
? t('callControls.toggleAudioButton.microphonePausedBySystem.title', 'Microphone is paused by your system')
|
|
1494
|
+
: (caption ??
|
|
1495
|
+
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
|
|
1333
1496
|
? 'preview-audio-unmute-button'
|
|
1334
1497
|
: 'preview-audio-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1335
1498
|
setTooltipDisabled(shown);
|
|
1336
1499
|
onMenuToggle?.(shown);
|
|
1337
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: !optionsAwareIsMute ? 'mic' : 'mic-off' }),
|
|
1500
|
+
}, 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] }) }));
|
|
1338
1501
|
};
|
|
1339
1502
|
const ToggleAudioPublishingButton = (props) => {
|
|
1340
|
-
const { t } =
|
|
1503
|
+
const { t } = useI18n();
|
|
1341
1504
|
const { caption, Menu = jsxRuntime.jsx(DeviceSelectorAudioInput, { visualType: "list" }), menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1342
1505
|
const { hasPermission, requestPermission, isAwaitingPermission } = useRequestPermission(videoClient.RequestPermissionRequestPermissionsEnum.SEND_AUDIO);
|
|
1343
1506
|
const { useMicrophoneState, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
@@ -1353,43 +1516,49 @@ const ToggleAudioPublishingButton = (props) => {
|
|
|
1353
1516
|
await microphone.toggle();
|
|
1354
1517
|
}
|
|
1355
1518
|
});
|
|
1356
|
-
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:
|
|
1357
|
-
? t('
|
|
1358
|
-
: !
|
|
1359
|
-
? t('
|
|
1360
|
-
:
|
|
1361
|
-
? t('
|
|
1362
|
-
:
|
|
1519
|
+
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
|
|
1520
|
+
? t('common.waitingForPermission.title', 'Waiting for permission')
|
|
1521
|
+
: !hasPermission
|
|
1522
|
+
? t('callControls.toggleAudioButton.noPermissionToShareAudio.title', 'You have no permission to share your audio')
|
|
1523
|
+
: !hasBrowserPermission
|
|
1524
|
+
? t('callControls.toggleAudioButton.checkBrowserMicPermissions.title', 'Check your browser mic permissions')
|
|
1525
|
+
: isSystemMuted
|
|
1526
|
+
? t('callControls.toggleAudioButton.microphonePausedBySystem.title', 'Microphone is paused by your system')
|
|
1527
|
+
: (caption ??
|
|
1528
|
+
t('callControls.toggleAudioButton.mic.title', 'Mic')), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, variant: optionsAwareIsMute ? 'destructive' : 'secondary', disabled: !hasBrowserPermission ||
|
|
1363
1529
|
!hasPermission ||
|
|
1364
1530
|
// disable button while the toggle action is pending when not using optimistic updates
|
|
1365
1531
|
(!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute ? 'audio-unmute-button' : 'audio-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, menuOffset: 16, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1366
1532
|
setTooltipDisabled(shown);
|
|
1367
1533
|
onMenuToggle?.(shown);
|
|
1368
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: optionsAwareIsMute ? 'mic-off' : 'mic' }),
|
|
1534
|
+
}, 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] }) }) }) }));
|
|
1369
1535
|
};
|
|
1370
1536
|
|
|
1371
1537
|
const ToggleVideoPreviewButton = (props) => {
|
|
1372
1538
|
const { caption, Menu = DeviceSelectorVideo, menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1373
|
-
const { t } =
|
|
1539
|
+
const { t } = useI18n();
|
|
1374
1540
|
const { useCameraState, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
1375
1541
|
const { camera, hasBrowserPermission, isPromptingPermission, isTogglePending, optionsAwareIsMute, } = useCameraState({ optimisticUpdates });
|
|
1376
1542
|
const localParticipant = useLocalParticipant();
|
|
1377
1543
|
const isSystemMuted = !!localParticipant?.interruptedTracks?.includes(videoClient.SfuModels.TrackType.VIDEO);
|
|
1378
1544
|
const [tooltipDisabled, setTooltipDisabled] = react.useState(false);
|
|
1379
1545
|
const handleClick = createCallControlHandler(props, () => camera.toggle());
|
|
1380
|
-
return (jsxRuntime.jsx(WithTooltip, { title:
|
|
1381
|
-
? t('
|
|
1382
|
-
:
|
|
1383
|
-
? t('
|
|
1384
|
-
:
|
|
1546
|
+
return (jsxRuntime.jsx(WithTooltip, { title: isPromptingPermission
|
|
1547
|
+
? t('common.waitingForPermission.title', 'Waiting for permission')
|
|
1548
|
+
: !hasBrowserPermission
|
|
1549
|
+
? t('callControls.toggleVideoButton.checkBrowserVideoPermissions.title', 'Check your browser video permissions')
|
|
1550
|
+
: isSystemMuted
|
|
1551
|
+
? t('callControls.toggleVideoButton.cameraPausedBySystem.title', 'Camera is paused by your system')
|
|
1552
|
+
: (caption ??
|
|
1553
|
+
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
|
|
1385
1554
|
? 'preview-video-unmute-button'
|
|
1386
1555
|
: 'preview-video-mute-button', onClick: handleClick, disabled: !hasBrowserPermission || (!optimisticUpdates && isTogglePending), Menu: Menu, menuPlacement: menuPlacement, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1387
1556
|
setTooltipDisabled(shown);
|
|
1388
1557
|
onMenuToggle?.(shown);
|
|
1389
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: !optionsAwareIsMute ? 'camera' : 'camera-off' }),
|
|
1558
|
+
}, 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] }) }));
|
|
1390
1559
|
};
|
|
1391
1560
|
const ToggleVideoPublishingButton = (props) => {
|
|
1392
|
-
const { t } =
|
|
1561
|
+
const { t } = useI18n();
|
|
1393
1562
|
const { caption, Menu = jsxRuntime.jsx(DeviceSelectorVideo, { visualType: "list" }), menuPlacement = 'top', onMenuToggle, optimisticUpdates, ...restCompositeButtonProps } = props;
|
|
1394
1563
|
const { hasPermission, requestPermission, isAwaitingPermission } = useRequestPermission(videoClient.RequestPermissionRequestPermissionsEnum.SEND_VIDEO);
|
|
1395
1564
|
const { useCameraState, useCallSettings, useLocalParticipant } = videoReactBindings.useCallStateHooks();
|
|
@@ -1407,36 +1576,37 @@ const ToggleVideoPublishingButton = (props) => {
|
|
|
1407
1576
|
await camera.toggle();
|
|
1408
1577
|
}
|
|
1409
1578
|
});
|
|
1410
|
-
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:
|
|
1411
|
-
? t('
|
|
1412
|
-
: !
|
|
1413
|
-
? t('
|
|
1414
|
-
: !
|
|
1415
|
-
? t('
|
|
1416
|
-
:
|
|
1417
|
-
? t('
|
|
1418
|
-
:
|
|
1579
|
+
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
|
|
1580
|
+
? t('common.waitingForPermission.title', 'Waiting for permission')
|
|
1581
|
+
: !hasPermission
|
|
1582
|
+
? t('callControls.toggleVideoButton.noPermissionToShareVideo.title', 'You have no permission to share your video')
|
|
1583
|
+
: !hasBrowserPermission
|
|
1584
|
+
? t('callControls.toggleVideoButton.checkBrowserVideoPermissions.title', 'Check your browser video permissions')
|
|
1585
|
+
: !isPublishingVideoAllowed
|
|
1586
|
+
? t('callControls.toggleVideoButton.videoPublishingDisabled.title', 'Video publishing is disabled by the system')
|
|
1587
|
+
: isSystemMuted
|
|
1588
|
+
? t('callControls.toggleVideoButton.cameraPausedBySystem.title', 'Camera is paused by your system')
|
|
1589
|
+
: caption ||
|
|
1590
|
+
t('callControls.toggleVideoButton.video.title', 'Video'), tooltipDisabled: tooltipDisabled, children: jsxRuntime.jsxs(CompositeButton, { active: optionsAwareIsMute, caption: caption, variant: optionsAwareIsMute ? 'destructive' : 'secondary', disabled: !hasBrowserPermission ||
|
|
1419
1591
|
!hasPermission ||
|
|
1420
1592
|
!isPublishingVideoAllowed ||
|
|
1421
1593
|
(!optimisticUpdates && isTogglePending), "data-testid": optionsAwareIsMute ? 'video-unmute-button' : 'video-mute-button', onClick: handleClick, Menu: Menu, menuPlacement: menuPlacement, menuOffset: 16, ...restCompositeButtonProps, onMenuToggle: (shown) => {
|
|
1422
1594
|
setTooltipDisabled(shown);
|
|
1423
1595
|
onMenuToggle?.(shown);
|
|
1424
|
-
}, children: [jsxRuntime.jsx(Icon, { icon: optionsAwareIsMute ? 'camera-off' : 'camera' }), (!hasBrowserPermission ||
|
|
1596
|
+
}, children: [jsxRuntime.jsx(Icon, { icon: optionsAwareIsMute ? 'camera-off' : 'camera' }), isPromptingPermission ? (jsxRuntime.jsx(Badge, { variant: "error", icon: "question-mark-fill" })) : !hasBrowserPermission ||
|
|
1425
1597
|
!hasPermission ||
|
|
1426
|
-
!isPublishingVideoAllowed
|
|
1427
|
-
|
|
1428
|
-
hasPermission &&
|
|
1429
|
-
isPublishingVideoAllowed && (jsxRuntime.jsx("span", { className: "str-video__system-muted", title: t('Camera is paused by your system'), children: "!" }))] }) }) }) }));
|
|
1598
|
+
!isPublishingVideoAllowed ||
|
|
1599
|
+
isSystemMuted ? (jsxRuntime.jsx(Badge, { variant: "error", icon: "exclamation-mark-fill" })) : null] }) }) }) }));
|
|
1430
1600
|
};
|
|
1431
1601
|
|
|
1432
1602
|
const EndCallMenu = (props) => {
|
|
1433
1603
|
const { onLeave, onEnd } = props;
|
|
1434
|
-
const { t } =
|
|
1435
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__end-call__confirmation", children: [jsxRuntime.jsxs("
|
|
1604
|
+
const { t } = useI18n();
|
|
1605
|
+
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')] }) })] }));
|
|
1436
1606
|
};
|
|
1437
1607
|
const CancelCallToggleMenuButton = react.forwardRef(function CancelCallToggleMenuButtonRender({ menuShown }, ref) {
|
|
1438
|
-
const { t } =
|
|
1439
|
-
return (jsxRuntime.jsx(WithTooltip, { title: t('Leave call'), tooltipDisabled: menuShown, children: jsxRuntime.jsx(IconButton, { icon: menuShown ? 'close' : 'call-end', variant:
|
|
1608
|
+
const { t } = useI18n();
|
|
1609
|
+
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 }) }));
|
|
1440
1610
|
});
|
|
1441
1611
|
const CancelCallConfirmButton = ({ onClick, onLeave, }) => {
|
|
1442
1612
|
const call = videoReactBindings.useCall();
|
|
@@ -1473,20 +1643,6 @@ const CancelCallConfirmButton = ({ onClick, onLeave, }) => {
|
|
|
1473
1643
|
return (jsxRuntime.jsx(MenuToggle, { placement: "top-start", ToggleButton: CancelCallToggleMenuButton, children: jsxRuntime.jsx(EndCallMenu, { onEnd: handleEndCall, onLeave: handleLeave }) }));
|
|
1474
1644
|
};
|
|
1475
1645
|
|
|
1476
|
-
react.lazy(() => Promise.resolve().then(function () { return require('./embedded-CallStatsLatencyChart-CpL1M_s0.cjs.js'); }));
|
|
1477
|
-
var Status;
|
|
1478
|
-
(function (Status) {
|
|
1479
|
-
Status["GOOD"] = "Good";
|
|
1480
|
-
Status["OK"] = "Ok";
|
|
1481
|
-
Status["BAD"] = "Bad";
|
|
1482
|
-
})(Status || (Status = {}));
|
|
1483
|
-
|
|
1484
|
-
react.forwardRef(function ToggleMenuButtonRender(props, ref) {
|
|
1485
|
-
const { t } = videoReactBindings.useI18n();
|
|
1486
|
-
const { caption, menuShown } = props;
|
|
1487
|
-
return (jsxRuntime.jsx(CompositeButton, { ref: ref, active: menuShown, caption: caption, title: caption || t('Statistics'), "data-testid": "stats-button", children: jsxRuntime.jsx(Icon, { icon: "stats" }) }));
|
|
1488
|
-
});
|
|
1489
|
-
|
|
1490
1646
|
const BlockedUserListing = ({ data }) => {
|
|
1491
1647
|
if (!data.length)
|
|
1492
1648
|
return null;
|
|
@@ -1498,34 +1654,43 @@ const BlockedUserListingItem = ({ userId }) => {
|
|
|
1498
1654
|
if (userId)
|
|
1499
1655
|
call?.unblockUser(userId);
|
|
1500
1656
|
};
|
|
1501
|
-
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(
|
|
1657
|
+
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" }) })] }));
|
|
1502
1658
|
};
|
|
1503
1659
|
|
|
1504
1660
|
const CallParticipantListHeader = ({ onClose, }) => {
|
|
1505
1661
|
const { useParticipants, useAnonymousParticipantCount } = videoReactBindings.useCallStateHooks();
|
|
1506
1662
|
const participants = useParticipants();
|
|
1507
1663
|
const anonymousParticipantCount = useAnonymousParticipantCount();
|
|
1508
|
-
const { t } =
|
|
1509
|
-
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('
|
|
1664
|
+
const { t } = useI18n();
|
|
1665
|
+
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" })] }));
|
|
1510
1666
|
};
|
|
1511
1667
|
|
|
1512
1668
|
const CallParticipantListingItem = react.memo(function CallParticipantListingItemRender({ participant, DisplayName = DefaultDisplayName, }) {
|
|
1513
1669
|
const isAudioOn = videoClient.hasAudio(participant);
|
|
1514
1670
|
const isVideoOn = videoClient.hasVideo(participant);
|
|
1515
1671
|
const isPinnedOn = videoClient.isPinned(participant);
|
|
1516
|
-
const { t } =
|
|
1517
|
-
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
|
|
1672
|
+
const { t } = useI18n();
|
|
1673
|
+
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
|
|
1674
|
+
? t('participantList.microphoneOn.title', 'Microphone on')
|
|
1675
|
+
: 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
|
|
1676
|
+
? t('participantList.cameraOn.title', 'Camera on')
|
|
1677
|
+
: 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, {}) }) })] })] }));
|
|
1518
1678
|
});
|
|
1519
1679
|
CallParticipantListingItem.displayName = 'CallParticipantListingItem';
|
|
1520
1680
|
const MediaIndicator = (props) => (jsxRuntime.jsx(WithTooltip, { ...props }));
|
|
1521
1681
|
const DefaultDisplayName = ({ participant }) => {
|
|
1522
1682
|
const connectedUser = videoReactBindings.useConnectedUser();
|
|
1523
|
-
const { t } =
|
|
1524
|
-
const meFlag = participant.userId === connectedUser?.id
|
|
1525
|
-
|
|
1683
|
+
const { t } = useI18n();
|
|
1684
|
+
const meFlag = participant.userId === connectedUser?.id
|
|
1685
|
+
? t('participantList.me.text', 'Me')
|
|
1686
|
+
: '';
|
|
1687
|
+
const nameOrId = participant.name ||
|
|
1688
|
+
participant.userId ||
|
|
1689
|
+
t('participantList.unknown.text', 'Unknown');
|
|
1526
1690
|
let displayName;
|
|
1527
1691
|
if (!participant.name) {
|
|
1528
|
-
displayName =
|
|
1692
|
+
displayName =
|
|
1693
|
+
meFlag || nameOrId || t('participantList.unknown.text', 'Unknown');
|
|
1529
1694
|
}
|
|
1530
1695
|
else if (meFlag) {
|
|
1531
1696
|
displayName = `${nameOrId} (${meFlag})`;
|
|
@@ -1536,14 +1701,14 @@ const DefaultDisplayName = ({ participant }) => {
|
|
|
1536
1701
|
return (jsxRuntime.jsx(WithTooltip, { className: "str-video__participant-listing-item__display-name", title: displayName, children: displayName }));
|
|
1537
1702
|
};
|
|
1538
1703
|
const ToggleButton$2 = react.forwardRef(function ToggleButtonRender(props, ref) {
|
|
1539
|
-
return jsxRuntime.jsx(IconButton, {
|
|
1704
|
+
return (jsxRuntime.jsx(IconButton, { className: "str-video__participant-listing-item__menu-button", active: props.menuShown, size: "sm", variant: "secondary", ref: ref, icon: "ellipsis" }));
|
|
1540
1705
|
});
|
|
1541
1706
|
|
|
1542
1707
|
const CallParticipantListing = ({ data, }) => (jsxRuntime.jsx("div", { className: "str-video__participant-listing", children: data.map((participant) => (jsxRuntime.jsx(CallParticipantListingItem, { participant: participant }, participant.sessionId))) }));
|
|
1543
1708
|
|
|
1544
1709
|
const EmptyParticipantSearchList = () => {
|
|
1545
|
-
const { t } =
|
|
1546
|
-
return (jsxRuntime.jsx("div", { className: "str-video__participant-list--empty", children: t('No participants found') }));
|
|
1710
|
+
const { t } = useI18n();
|
|
1711
|
+
return (jsxRuntime.jsx("div", { className: "str-video__participant-list--empty", children: t('participantList.noParticipantsFound.text', 'No participants found') }));
|
|
1547
1712
|
};
|
|
1548
1713
|
|
|
1549
1714
|
const SearchInput = ({ exitSearch, isActive, ...rest }) => {
|
|
@@ -1563,7 +1728,7 @@ const SearchInput = ({ exitSearch, isActive, ...rest }) => {
|
|
|
1563
1728
|
}, [inputElement]);
|
|
1564
1729
|
return (jsxRuntime.jsxs("div", { className: clsx('str-video__search-input__container', {
|
|
1565
1730
|
'str-video__search-input__container--active': isActive,
|
|
1566
|
-
}), children: [jsxRuntime.jsx("input", { placeholder: "Search", ...rest, ref: setInputElement }), isActive
|
|
1731
|
+
}), 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" }) }))] }));
|
|
1567
1732
|
};
|
|
1568
1733
|
|
|
1569
1734
|
function SearchResults({ EmptySearchResultComponent, LoadingIndicator: LoadingIndicator$1 = LoadingIndicator, searchQueryInProgress, searchResults, SearchResultList, }) {
|
|
@@ -1622,11 +1787,11 @@ const CallParticipantsList = ({ onClose, activeUsersSearchFn, blockedUsersSearch
|
|
|
1622
1787
|
};
|
|
1623
1788
|
const CallParticipantListContentHeader = ({ userListType, setUserListType, }) => {
|
|
1624
1789
|
const call = videoReactBindings.useCall();
|
|
1625
|
-
const { t } =
|
|
1790
|
+
const { t } = useI18n();
|
|
1626
1791
|
const muteAll = react.useCallback(() => {
|
|
1627
1792
|
call?.muteAllUsers('audio');
|
|
1628
1793
|
}, [call]);
|
|
1629
|
-
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(
|
|
1794
|
+
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))) }) })] }));
|
|
1630
1795
|
};
|
|
1631
1796
|
const ActiveUsersSearchResults = ({ searchQuery, activeUsersSearchFn: activeUsersSearchFnFromProps, debounceSearchInterval, }) => {
|
|
1632
1797
|
const { useParticipants } = videoReactBindings.useCallStateHooks();
|
|
@@ -1667,7 +1832,7 @@ const BlockedUsersSearchResults = ({ blockedUsersSearchFn: blockedUsersSearchFnF
|
|
|
1667
1832
|
return (jsxRuntime.jsx(SearchResults, { EmptySearchResultComponent: EmptyParticipantSearchList, LoadingIndicator: LoadingIndicator, searchQueryInProgress: searchQueryInProgress, searchResults: searchQuery ? searchResults : blockedUsers, SearchResultList: BlockedUserListing }));
|
|
1668
1833
|
};
|
|
1669
1834
|
const ToggleButton$1 = react.forwardRef(function ToggleButtonRender(props, ref) {
|
|
1670
|
-
return jsxRuntime.jsx(IconButton, {
|
|
1835
|
+
return (jsxRuntime.jsx(IconButton, { className: "str-video__participant-list__filter-button", active: props.menuShown, size: "sm", variant: "secondary", ref: ref, icon: "filter" }));
|
|
1671
1836
|
});
|
|
1672
1837
|
|
|
1673
1838
|
const NoiseCancellationContext = react.createContext(null);
|
|
@@ -1748,19 +1913,6 @@ const NoiseCancellationProvider = (props) => {
|
|
|
1748
1913
|
return (jsxRuntime.jsx(NoiseCancellationContext.Provider, { value: contextValue, children: children }));
|
|
1749
1914
|
};
|
|
1750
1915
|
|
|
1751
|
-
({
|
|
1752
|
-
[videoClient.CallingState.JOINING]: 'Joining',
|
|
1753
|
-
[videoClient.CallingState.RINGING]: 'Ringing',
|
|
1754
|
-
[videoClient.CallingState.MIGRATING]: 'Migrating',
|
|
1755
|
-
[videoClient.CallingState.RECONNECTING]: 'Re-connecting',
|
|
1756
|
-
[videoClient.CallingState.RECONNECTING_FAILED]: 'Failed',
|
|
1757
|
-
[videoClient.CallingState.OFFLINE]: 'No internet connection',
|
|
1758
|
-
[videoClient.CallingState.IDLE]: '',
|
|
1759
|
-
[videoClient.CallingState.UNKNOWN]: '',
|
|
1760
|
-
[videoClient.CallingState.JOINED]: 'Joined',
|
|
1761
|
-
[videoClient.CallingState.LEFT]: 'Left call',
|
|
1762
|
-
});
|
|
1763
|
-
|
|
1764
1916
|
const byNameOrId = (a, b) => {
|
|
1765
1917
|
if (a.name && b.name && a.name < b.name)
|
|
1766
1918
|
return -1;
|
|
@@ -1810,7 +1962,7 @@ const PermissionRequests = () => {
|
|
|
1810
1962
|
// don't render anything if there are no permission requests
|
|
1811
1963
|
if (permissionRequests.length === 0)
|
|
1812
1964
|
return null;
|
|
1813
|
-
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, {
|
|
1965
|
+
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: () => {
|
|
1814
1966
|
setExpanded((e) => !e);
|
|
1815
1967
|
}, children: expanded ? 'Hide requests' : 'Show requests' })] }), expanded && (jsxRuntime.jsx(PermissionRequestList, { ref: refs.setFloating, style: {
|
|
1816
1968
|
position: strategy,
|
|
@@ -1821,51 +1973,71 @@ const PermissionRequests = () => {
|
|
|
1821
1973
|
};
|
|
1822
1974
|
const PermissionRequestList = react.forwardRef(function PermissionRequestListRender(props, ref) {
|
|
1823
1975
|
const { permissionRequests, handleUpdatePermission, ...rest } = props;
|
|
1824
|
-
const { t } =
|
|
1976
|
+
const { t } = useI18n();
|
|
1825
1977
|
return (jsxRuntime.jsx("div", { className: "str-video__permission-requests-list", ref: ref, ...rest, children: permissionRequests.map((request, reqIndex) => {
|
|
1826
1978
|
const { user, permissions } = request;
|
|
1827
|
-
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",
|
|
1979
|
+
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}`));
|
|
1828
1980
|
}) }));
|
|
1829
1981
|
});
|
|
1830
|
-
const Button = (props) => {
|
|
1831
|
-
const { className, ...rest } = props;
|
|
1832
|
-
return (jsxRuntime.jsx("button", { className: clsx('str-video__permission-request__button', className), ...rest }));
|
|
1833
|
-
};
|
|
1834
1982
|
const messageForPermission = (userName, permission, t) => {
|
|
1835
1983
|
switch (permission) {
|
|
1836
1984
|
case videoClient.OwnCapability.SEND_AUDIO:
|
|
1837
|
-
return t('{{ userName }} is requesting to speak', { userName });
|
|
1985
|
+
return t('permissions.requestingToSpeak.text', '{{ userName }} is requesting to speak', { userName });
|
|
1838
1986
|
case videoClient.OwnCapability.SEND_VIDEO:
|
|
1839
|
-
return t('{{ userName }} is requesting to share their camera', {
|
|
1987
|
+
return t('permissions.requestingCamera.text', '{{ userName }} is requesting to share their camera', {
|
|
1840
1988
|
userName,
|
|
1841
1989
|
});
|
|
1842
1990
|
case videoClient.OwnCapability.SCREENSHARE:
|
|
1843
|
-
return t('{{ userName }} is requesting to present their screen', {
|
|
1991
|
+
return t('permissions.requestingScreenShare.text', '{{ userName }} is requesting to present their screen', {
|
|
1844
1992
|
userName,
|
|
1845
1993
|
});
|
|
1846
1994
|
default:
|
|
1847
|
-
return t('{{ userName }} is requesting permission: {{ permission }}', {
|
|
1995
|
+
return t('permissions.requestingPermission.text', '{{ userName }} is requesting permission: {{ permission }}', {
|
|
1848
1996
|
userName,
|
|
1849
1997
|
permission,
|
|
1850
1998
|
});
|
|
1851
1999
|
}
|
|
1852
2000
|
};
|
|
1853
2001
|
|
|
1854
|
-
const StreamTheme = ({ as: Component = 'div', className, children, ...props }) => {
|
|
1855
|
-
return (jsxRuntime.jsx(Component, { ...props, className: clsx('str-video', className), children: children }));
|
|
2002
|
+
const StreamTheme = ({ as: Component = 'div', className, children, theme = 'str-video__theme-dark', ...props }) => {
|
|
2003
|
+
return (jsxRuntime.jsx(Component, { ...props, className: clsx('str-video', theme, className), children: children }));
|
|
1856
2004
|
};
|
|
1857
2005
|
|
|
1858
2006
|
const DefaultDisabledVideoPreview = () => {
|
|
1859
|
-
const { t } =
|
|
1860
|
-
return (jsxRuntime.jsx("div", { className: "str_video__video-preview__disabled-video-preview", children: t('Video is disabled') }));
|
|
2007
|
+
const { t } = useI18n();
|
|
2008
|
+
return (jsxRuntime.jsx("div", { className: "str_video__video-preview__disabled-video-preview", children: t('common.videoDisabled.text', 'Video is disabled') }));
|
|
1861
2009
|
};
|
|
1862
2010
|
const DefaultNoCameraPreview = () => {
|
|
1863
|
-
const { t } =
|
|
1864
|
-
return (jsxRuntime.jsx("div", { className: "str_video__video-preview__no-camera-preview", children: t('No camera found') }));
|
|
2011
|
+
const { t } = useI18n();
|
|
2012
|
+
return (jsxRuntime.jsx("div", { className: "str_video__video-preview__no-camera-preview", children: t('common.noCameraFound.text', 'No camera found') }));
|
|
1865
2013
|
};
|
|
1866
|
-
|
|
2014
|
+
/**
|
|
2015
|
+
* Reports whether the local user is currently speaking, before they join the
|
|
2016
|
+
* call. `MicrophoneManager` only runs its detector while the microphone is
|
|
2017
|
+
* muted (for `speakingWhileMuted`), so this mirrors `AudioVolumeIndicator` and
|
|
2018
|
+
* runs one on the live microphone stream instead.
|
|
2019
|
+
*/
|
|
2020
|
+
const useLocalSpeaking = (enabled) => {
|
|
2021
|
+
const { useMicrophoneState } = videoReactBindings.useCallStateHooks();
|
|
2022
|
+
const { isEnabled, mediaStream } = useMicrophoneState();
|
|
2023
|
+
const [isSpeaking, setIsSpeaking] = react.useState(false);
|
|
2024
|
+
react.useEffect(() => {
|
|
2025
|
+
if (!enabled || !isEnabled || !mediaStream) {
|
|
2026
|
+
setIsSpeaking(false);
|
|
2027
|
+
return;
|
|
2028
|
+
}
|
|
2029
|
+
const dispose = videoClient.createSoundDetector(mediaStream, ({ isSoundDetected }) => setIsSpeaking(isSoundDetected), { detectionFrequencyInMs: 80, destroyStreamOnStop: false });
|
|
2030
|
+
return () => {
|
|
2031
|
+
setIsSpeaking(false);
|
|
2032
|
+
dispose().catch(console.error);
|
|
2033
|
+
};
|
|
2034
|
+
}, [enabled, isEnabled, mediaStream]);
|
|
2035
|
+
return isSpeaking;
|
|
2036
|
+
};
|
|
2037
|
+
const VideoPreview = ({ className, mirror = true, DisabledVideoPreview = DefaultDisabledVideoPreview, NoCameraPreview = DefaultNoCameraPreview, StartingCameraPreview = LoadingIndicator, speakingIndicatorVisible = false, }) => {
|
|
1867
2038
|
const { useCameraState } = videoReactBindings.useCallStateHooks();
|
|
1868
2039
|
const { devices, status, isMute, mediaStream } = useCameraState();
|
|
2040
|
+
const isSpeaking = useLocalSpeaking(speakingIndicatorVisible);
|
|
1869
2041
|
let contents;
|
|
1870
2042
|
if (isMute && devices?.length === 0) {
|
|
1871
2043
|
contents = jsxRuntime.jsx(NoCameraPreview, {});
|
|
@@ -1880,21 +2052,43 @@ const VideoPreview = ({ className, mirror = true, DisabledVideoPreview = Default
|
|
|
1880
2052
|
else {
|
|
1881
2053
|
contents = jsxRuntime.jsx(DisabledVideoPreview, {});
|
|
1882
2054
|
}
|
|
1883
|
-
return (jsxRuntime.jsx("div", { className: clsx('str-video__video-preview-container', className
|
|
2055
|
+
return (jsxRuntime.jsx("div", { className: clsx('str-video__video-preview-container', className, {
|
|
2056
|
+
'str-video__video-preview-container--speaking': isSpeaking,
|
|
2057
|
+
}), children: contents }));
|
|
2058
|
+
};
|
|
2059
|
+
|
|
2060
|
+
/** How many of the three bars are lit, per quality level. */
|
|
2061
|
+
const ACTIVE_BARS = {
|
|
2062
|
+
[videoClient.SfuModels.ConnectionQuality.POOR]: 1,
|
|
2063
|
+
[videoClient.SfuModels.ConnectionQuality.GOOD]: 2,
|
|
2064
|
+
[videoClient.SfuModels.ConnectionQuality.EXCELLENT]: 3,
|
|
2065
|
+
};
|
|
2066
|
+
const BAR_COUNT = 3;
|
|
2067
|
+
/**
|
|
2068
|
+
* Three ascending bars showing a participant's connection quality.
|
|
2069
|
+
*/
|
|
2070
|
+
const ConnectionQualityIndicator = ({ quality, title, className, }) => {
|
|
2071
|
+
const activeBars = ACTIVE_BARS[quality];
|
|
2072
|
+
if (!activeBars)
|
|
2073
|
+
return null;
|
|
2074
|
+
const level = videoClient.SfuModels.ConnectionQuality[quality].toLowerCase();
|
|
2075
|
+
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 &&
|
|
2076
|
+
'str-video__connection-quality-indicator__bar--active') }, index))) }));
|
|
1884
2077
|
};
|
|
1885
2078
|
|
|
1886
2079
|
const ToggleButton = react.forwardRef(function ToggleButtonRender(props, ref) {
|
|
1887
|
-
|
|
2080
|
+
const { t } = useI18n();
|
|
2081
|
+
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" }));
|
|
1888
2082
|
});
|
|
1889
2083
|
const DefaultScreenShareOverlay = () => {
|
|
1890
2084
|
const call = videoReactBindings.useCall();
|
|
1891
|
-
const { t } =
|
|
2085
|
+
const { t } = useI18n();
|
|
1892
2086
|
const stopScreenShare = () => {
|
|
1893
2087
|
call?.screenShare.disable().catch((err) => {
|
|
1894
2088
|
console.error('Failed to stop screen sharing:', err);
|
|
1895
2089
|
});
|
|
1896
2090
|
};
|
|
1897
|
-
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(
|
|
2091
|
+
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')] })] }));
|
|
1898
2092
|
};
|
|
1899
2093
|
/**
|
|
1900
2094
|
* Rendered over a remote participant's tile when the browser's autoplay policy
|
|
@@ -1903,8 +2097,8 @@ const DefaultScreenShareOverlay = () => {
|
|
|
1903
2097
|
*/
|
|
1904
2098
|
const DefaultAudioBlockedNotification = () => {
|
|
1905
2099
|
const call = videoReactBindings.useCall();
|
|
1906
|
-
const { t } =
|
|
1907
|
-
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') })] })] }) }));
|
|
2100
|
+
const { t } = useI18n();
|
|
2101
|
+
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') })] })] }) }));
|
|
1908
2102
|
};
|
|
1909
2103
|
const DefaultParticipantViewUI = ({ indicatorsVisible = true, menuPlacement = 'bottom-start', showMenuButton = true, ParticipantActionsContextMenu: ParticipantActionsContextMenu$1 = ParticipantActionsContextMenu, AudioBlockedNotification = DefaultAudioBlockedNotification, }) => {
|
|
1910
2104
|
const { participant, trackType } = useParticipantViewContext();
|
|
@@ -1925,17 +2119,17 @@ const ParticipantDetails = ({ indicatorsVisible = true, }) => {
|
|
|
1925
2119
|
const { participant, trackType } = useParticipantViewContext();
|
|
1926
2120
|
const { isLocalParticipant, connectionQuality, pin, sessionId, name, userId, } = participant;
|
|
1927
2121
|
const call = videoReactBindings.useCall();
|
|
1928
|
-
const { t } =
|
|
1929
|
-
const connectionQualityAsString = !!connectionQuality &&
|
|
1930
|
-
videoClient.SfuModels.ConnectionQuality[connectionQuality].toLowerCase();
|
|
2122
|
+
const { t } = useI18n();
|
|
1931
2123
|
const hasAudioTrack = videoClient.hasAudio(participant);
|
|
1932
2124
|
const hasVideoTrack = videoClient.hasVideo(participant);
|
|
1933
2125
|
const canUnpin = !!pin && pin.isLocalPin;
|
|
1934
2126
|
const isTrackPaused = trackType !== 'none' ? videoClient.hasPausedTrack(participant, trackType) : false;
|
|
1935
2127
|
const isAudioConnecting = videoReactBindings.useIsAudioConnecting(participant);
|
|
1936
2128
|
const isVideoConnecting = videoReactBindings.useIsVideoConnecting(participant);
|
|
1937
|
-
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
|
|
1938
|
-
|
|
2129
|
+
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
|
|
2130
|
+
? t('participantView.unpin.label', 'Unpin')
|
|
2131
|
+
: 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 &&
|
|
2132
|
+
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 })) }))] }));
|
|
1939
2133
|
};
|
|
1940
2134
|
const SpeechIndicator = () => {
|
|
1941
2135
|
const { participant } = useParticipantViewContext();
|
|
@@ -1985,7 +2179,7 @@ const ParticipantView = react.memo(react.forwardRef(function ParticipantViewRend
|
|
|
1985
2179
|
applyElementToRef(ref, element);
|
|
1986
2180
|
setTrackedElement(element);
|
|
1987
2181
|
}, className: clsx('str-video__participant-view', isDominantSpeaker &&
|
|
1988
|
-
'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
|
|
2182
|
+
'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 ||
|
|
1989
2183
|
trackType !== 'videoTrack' ||
|
|
1990
2184
|
isParticipantVideoEnabled(participant.sessionId), mirror: mirror, autoPlay: true }), isComponentType(ParticipantViewUI) ? (jsxRuntime.jsx(ParticipantViewUI, {})) : (ParticipantViewUI)] }) }));
|
|
1991
2185
|
}));
|
|
@@ -1995,185 +2189,27 @@ ParticipantView.displayName = 'ParticipantView';
|
|
|
1995
2189
|
const StreamCall = videoReactBindings.StreamCallProvider;
|
|
1996
2190
|
StreamCall.displayName = 'StreamCall';
|
|
1997
2191
|
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
var Block = "Block";
|
|
2020
|
-
var Kick = "Kick";
|
|
2021
|
-
var Enter = "Enter";
|
|
2022
|
-
var Leave = "Leave";
|
|
2023
|
-
var Participants = "Participants";
|
|
2024
|
-
var Anonymous = ", and ({{ count }}) anonymous";
|
|
2025
|
-
var Speaker = "Speaker";
|
|
2026
|
-
var Microphone = "Microphone";
|
|
2027
|
-
var Backstage = "Backstage";
|
|
2028
|
-
var en = {
|
|
2029
|
-
Joining: Joining,
|
|
2030
|
-
Mic: Mic,
|
|
2031
|
-
"No internet connection": "No internet connection",
|
|
2032
|
-
"Re-connecting": "Re-connecting",
|
|
2033
|
-
Ringing: Ringing,
|
|
2034
|
-
"Screen Share": "Screen Share",
|
|
2035
|
-
"Select a Camera": "Select a Camera",
|
|
2036
|
-
"Select a Mic": "Select a Mic",
|
|
2037
|
-
"Select Speakers": "Select Speakers",
|
|
2038
|
-
Speakers: Speakers,
|
|
2039
|
-
Video: Video,
|
|
2040
|
-
"You are muted. Unmute to speak.": "You are muted. Unmute to speak.",
|
|
2041
|
-
"Background filters performance is degraded. Consider disabling filters for better performance.": "Background filters performance is degraded. Consider disabling filters for better performance.",
|
|
2042
|
-
Live: Live,
|
|
2043
|
-
"Livestream starts soon": "Livestream starts soon",
|
|
2044
|
-
"Livestream starts at {{ time }}": "Livestream starts at {{ time }}",
|
|
2045
|
-
"{{ count }} participants joined early_one": "{{ count }} participant joined early",
|
|
2046
|
-
"{{ count }} participants joined early_other": "{{ count }} participants joined early",
|
|
2047
|
-
"You can now speak.": "You can now speak.",
|
|
2048
|
-
"Awaiting for an approval to speak.": "Awaiting for an approval to speak.",
|
|
2049
|
-
"You can no longer speak.": "You can no longer speak.",
|
|
2050
|
-
"You can now share your video.": "You can now share your video.",
|
|
2051
|
-
"Awaiting for an approval to share your video.": "Awaiting for an approval to share your video.",
|
|
2052
|
-
"You can no longer share your video.": "You can no longer share your video.",
|
|
2053
|
-
"Waiting for recording to stop...": "Waiting for recording to stop...",
|
|
2054
|
-
"Waiting for recording to start...": "Waiting for recording to start...",
|
|
2055
|
-
"Record call": "Record call",
|
|
2056
|
-
Reactions: Reactions,
|
|
2057
|
-
Statistics: Statistics,
|
|
2058
|
-
"You can now share your screen.": "You can now share your screen.",
|
|
2059
|
-
"Awaiting for an approval to share screen.": "Awaiting for an approval to share screen.",
|
|
2060
|
-
"You can no longer share your screen.": "You can no longer share your screen.",
|
|
2061
|
-
"Share screen": "Share screen",
|
|
2062
|
-
"Incoming Call...": "Incoming Call...",
|
|
2063
|
-
"Calling...": "Calling...",
|
|
2064
|
-
"Mute All": "Mute All",
|
|
2065
|
-
Invite: Invite,
|
|
2066
|
-
Join: Join,
|
|
2067
|
-
You: You,
|
|
2068
|
-
Me: Me,
|
|
2069
|
-
Unknown: Unknown,
|
|
2070
|
-
"Toggle device menu": "Toggle device menu",
|
|
2071
|
-
Default: Default,
|
|
2072
|
-
"Call Recordings": "Call Recordings",
|
|
2073
|
-
Refresh: Refresh,
|
|
2074
|
-
"Check your browser video permissions": "Check your browser video permissions",
|
|
2075
|
-
"Video publishing is disabled by the system": "Video publishing is disabled by the system",
|
|
2076
|
-
"You have no permission to share your video": "You have no permission to share your video",
|
|
2077
|
-
"You have no permission to share your audio": "You have no permission to share your audio",
|
|
2078
|
-
"You are presenting your screen": "You are presenting your screen",
|
|
2079
|
-
"Stop Screen Sharing": "Stop Screen Sharing",
|
|
2080
|
-
"Audio is blocked by your system": "Audio is blocked by your system",
|
|
2081
|
-
"Click or tap to play audio": "Click or tap to play audio",
|
|
2082
|
-
Allow: Allow,
|
|
2083
|
-
Revoke: Revoke,
|
|
2084
|
-
Dismiss: Dismiss,
|
|
2085
|
-
"Microphone on": "Microphone on",
|
|
2086
|
-
"Microphone off": "Microphone off",
|
|
2087
|
-
"Microphone is paused by your system": "Microphone is paused by your system",
|
|
2088
|
-
"Camera on": "Camera on",
|
|
2089
|
-
"Camera off": "Camera off",
|
|
2090
|
-
"Camera is paused by your system": "Camera is paused by your system",
|
|
2091
|
-
"No camera found": "No camera found",
|
|
2092
|
-
"Video is disabled": "Video is disabled",
|
|
2093
|
-
Pinned: Pinned,
|
|
2094
|
-
Unpin: Unpin,
|
|
2095
|
-
Pin: Pin,
|
|
2096
|
-
"Pin for everyone": "Pin for everyone",
|
|
2097
|
-
"Unpin for everyone": "Unpin for everyone",
|
|
2098
|
-
Block: Block,
|
|
2099
|
-
Kick: Kick,
|
|
2100
|
-
"Turn off video": "Turn off video",
|
|
2101
|
-
"Turn off screen share": "Turn off screen share",
|
|
2102
|
-
"Mute audio": "Mute audio",
|
|
2103
|
-
"Mute screen share audio": "Mute screen share audio",
|
|
2104
|
-
"Allow audio": "Allow audio",
|
|
2105
|
-
"Allow video": "Allow video",
|
|
2106
|
-
"Allow screen sharing": "Allow screen sharing",
|
|
2107
|
-
"Disable audio": "Disable audio",
|
|
2108
|
-
"Disable video": "Disable video",
|
|
2109
|
-
"Disable screen sharing": "Disable screen sharing",
|
|
2110
|
-
Enter: Enter,
|
|
2111
|
-
Leave: Leave,
|
|
2112
|
-
"Leave call": "Leave call",
|
|
2113
|
-
"End call for all": "End call for all",
|
|
2114
|
-
"{{ direction }} fullscreen": "{{ direction }} fullscreen",
|
|
2115
|
-
"{{ direction }} picture-in-picture": "{{ direction }} picture-in-picture",
|
|
2116
|
-
"Dominant Speaker": "Dominant Speaker",
|
|
2117
|
-
"Poor connection quality": "Poor connection quality. Please check your internet connection.",
|
|
2118
|
-
"Video paused due to insufficient bandwidth": "Video paused due to insufficient bandwidth",
|
|
2119
|
-
"Audio is connecting...": "Audio is connecting...",
|
|
2120
|
-
"Video is connecting...": "Video is connecting...",
|
|
2121
|
-
Participants: Participants,
|
|
2122
|
-
Anonymous: Anonymous,
|
|
2123
|
-
"No participants found": "No participants found",
|
|
2124
|
-
"Participants ({{ numberOfParticipants }})": "Participants ({{ numberOfParticipants }})",
|
|
2125
|
-
"{{ userName }} is sharing their screen": "{{ userName }} is sharing their screen",
|
|
2126
|
-
"{{ userName }} is requesting to speak": "{{ userName }} is requesting to speak",
|
|
2127
|
-
"{{ userName }} is requesting to share their camera": "{{ userName }} is requesting to share their camera",
|
|
2128
|
-
"{{ userName }} is requesting to present their screen": "{{ userName }} is requesting to present their screen",
|
|
2129
|
-
"{{ userName }} is requesting permission: {{ permission }}": "{{ userName }} is requesting permission: {{ permission }}",
|
|
2130
|
-
"Applying...": "Applying...",
|
|
2131
|
-
"Disable blur": "Disable blur",
|
|
2132
|
-
"Blur background": "Blur background",
|
|
2133
|
-
"Migrating...": "Migrating...",
|
|
2134
|
-
"Reconnecting...": "Reconnecting...",
|
|
2135
|
-
"You are offline. Check your internet connection.": "You are offline. Check your internet connection.",
|
|
2136
|
-
"Failed to restore connection. Please try again.": "Failed to restore connection. Please try again.",
|
|
2137
|
-
"Failed to join. Please try again.": "Failed to join. Please try again.",
|
|
2138
|
-
"Set up your call before joining": "Set up your call before joining",
|
|
2139
|
-
"Please grant your browser permission to access your camera and microphone.": "Please grant your browser permission to access your camera and microphone.",
|
|
2140
|
-
"Start call": "Start call",
|
|
2141
|
-
Speaker: Speaker,
|
|
2142
|
-
Microphone: Microphone,
|
|
2143
|
-
Backstage: Backstage,
|
|
2144
|
-
"Go Live": "Go Live",
|
|
2145
|
-
"Stop Live": "End Live",
|
|
2146
|
-
"Enter Backstage": "Enter Backstage",
|
|
2147
|
-
"Prepare your livestream": "Prepare your livestream",
|
|
2148
|
-
"Ready to go live": "Ready to go live",
|
|
2149
|
-
"Stream is ready!": "Stream is ready!",
|
|
2150
|
-
"Waiting for the livestream to start": "Waiting for the livestream to start",
|
|
2151
|
-
"{{ count }} waiting": "{{ count }} waiting",
|
|
2152
|
-
"Join Stream": "Join Stream",
|
|
2153
|
-
"Join automatically when stream starts": "Join automatically when stream starts",
|
|
2154
|
-
"Display name": "Display name",
|
|
2155
|
-
"Permission needed": "Permission needed",
|
|
2156
|
-
"Call ended": "Call ended",
|
|
2157
|
-
"Rejoin call": "Rejoin call",
|
|
2158
|
-
"Left by mistake?": "Left by mistake?",
|
|
2159
|
-
"Help us improve": "Help us improve",
|
|
2160
|
-
"Leave feedback": "Leave feedback",
|
|
2161
|
-
"Failed to rejoin. Please try again.": "Failed to rejoin. Please try again.",
|
|
2162
|
-
"Share your feedback": "Share your feedback",
|
|
2163
|
-
"Tell us about your experience...": "Tell us about your experience...",
|
|
2164
|
-
"Submit feedback": "Submit feedback",
|
|
2165
|
-
"Feedback message": "Feedback message",
|
|
2166
|
-
"How was your call quality?": "How was your call quality?",
|
|
2167
|
-
"Rate {{ count }} star_one": "Rate {{ count }} star",
|
|
2168
|
-
"Rate {{ count }} star_other": "Rate {{ count }} stars",
|
|
2169
|
-
"Thank you!": "Thank you!",
|
|
2170
|
-
"Your feedback helps improve call quality.": "Your feedback helps improve call quality."
|
|
2171
|
-
};
|
|
2172
|
-
|
|
2173
|
-
const translations = { en };
|
|
2174
|
-
|
|
2175
|
-
const StreamVideo = (props) => {
|
|
2176
|
-
return (jsxRuntime.jsx(videoReactBindings.StreamVideoProvider, { translationsOverrides: translations, ...props }));
|
|
2192
|
+
/**
|
|
2193
|
+
* StreamVideo is the root provider of the SDK: it provides the client to the component tree and
|
|
2194
|
+
* mounts the SDK's translation context.
|
|
2195
|
+
*
|
|
2196
|
+
* The i18n runtime lives here rather than in `@stream-io/video-react-bindings` because the key
|
|
2197
|
+
* catalog is generated from *this* package's `t()` call sites.
|
|
2198
|
+
*
|
|
2199
|
+
* This also fixes a real bug in the previous implementation, which rendered
|
|
2200
|
+
* `<StreamVideoProvider translationsOverrides={translations} {...props} />`. Because `{...props}`
|
|
2201
|
+
* came last, an integrator passing `translationsOverrides` *replaced* the SDK's bundled strings
|
|
2202
|
+
* instead of merging with them, leaving every untranslated key rendering as a raw dotted path.
|
|
2203
|
+
* `useStreami18n` layers integrator dictionaries over the SDK's own defaults, so a partial
|
|
2204
|
+
* dictionary is now safe.
|
|
2205
|
+
*/
|
|
2206
|
+
const StreamVideo = ({ children, client, i18nInstance, language, translations, }) => {
|
|
2207
|
+
const translationContext = useStreami18n({
|
|
2208
|
+
i18nInstance,
|
|
2209
|
+
language,
|
|
2210
|
+
translations,
|
|
2211
|
+
});
|
|
2212
|
+
return (jsxRuntime.jsx(videoReactBindings.StreamVideoProvider, { client: client, children: jsxRuntime.jsx(TranslationProvider, { value: translationContext, children: children }) }));
|
|
2177
2213
|
};
|
|
2178
2214
|
StreamVideo.displayName = 'StreamVideo';
|
|
2179
2215
|
|
|
@@ -2364,14 +2400,14 @@ const ParticipantOverlay = (props) => {
|
|
|
2364
2400
|
const toggleFullScreen = useToggleFullScreen();
|
|
2365
2401
|
const { speaker, volume } = useSpeakerState();
|
|
2366
2402
|
const isSpeakerMuted = volume === 0;
|
|
2367
|
-
const { t } =
|
|
2368
|
-
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.
|
|
2369
|
-
|
|
2370
|
-
|
|
2403
|
+
const { t } = useI18n();
|
|
2404
|
+
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
|
|
2405
|
+
? videoClient.humanize(participantCount)
|
|
2406
|
+
: 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 &&
|
|
2371
2407
|
'str-video__livestream-layout__mute-button--muted'), onClick: () => speaker.setVolume(isSpeakerMuted ? 1 : 0) })), enableFullScreen &&
|
|
2372
2408
|
participantViewElement &&
|
|
2373
2409
|
typeof participantViewElement.requestFullscreen !==
|
|
2374
|
-
'undefined' && (jsxRuntime.jsx("
|
|
2410
|
+
'undefined' && (jsxRuntime.jsx(IconButton, { icon: "fullscreen", variant: "secondary", appearance: "solid", size: "sm", className: "str-video__livestream-layout__go-fullscreen", onClick: toggleFullScreen }))] })] })) }));
|
|
2375
2411
|
};
|
|
2376
2412
|
const useUpdateCallDuration = () => {
|
|
2377
2413
|
const { useIsCallLive, useCallSession } = videoReactBindings.useCallStateHooks();
|
|
@@ -2436,6 +2472,7 @@ const PaginatedGridLayoutGroup = ({ group, mirror, VideoPlaceholder, PictureInPi
|
|
|
2436
2472
|
}), children: group.map((participant) => (jsxRuntime.jsx(ParticipantView, { participant: participant, muteAudio: true, mirror: mirror, VideoPlaceholder: VideoPlaceholder, PictureInPicturePlaceholder: PictureInPicturePlaceholder, ParticipantViewUI: ParticipantViewUI }, participant.sessionId))) }));
|
|
2437
2473
|
};
|
|
2438
2474
|
const PaginatedGridLayout = (props) => {
|
|
2475
|
+
const { t } = useI18n();
|
|
2439
2476
|
const { groupSize = (props.groupSize || 0) > 0
|
|
2440
2477
|
? props.groupSize || GROUP_SIZE
|
|
2441
2478
|
: GROUP_SIZE, excludeLocalParticipant = false, filterParticipants, mirrorLocalParticipantVideo = true, pageArrowsVisible = true, VideoPlaceholder, ParticipantViewUI = DefaultParticipantViewUI, PictureInPicturePlaceholder, muted, } = props;
|
|
@@ -2467,7 +2504,7 @@ const PaginatedGridLayout = (props) => {
|
|
|
2467
2504
|
const mirror = mirrorLocalParticipantVideo ? undefined : false;
|
|
2468
2505
|
if (!call)
|
|
2469
2506
|
return null;
|
|
2470
|
-
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)) }))] })] }));
|
|
2507
|
+
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)) }))] })] }));
|
|
2471
2508
|
};
|
|
2472
2509
|
PaginatedGridLayout.displayName = 'PaginatedGridLayout';
|
|
2473
2510
|
|
|
@@ -2572,6 +2609,7 @@ const SpeakerLayout = ({ ParticipantViewUIBar = DefaultParticipantViewUIBar, Par
|
|
|
2572
2609
|
};
|
|
2573
2610
|
SpeakerLayout.displayName = 'SpeakerLayout';
|
|
2574
2611
|
const HorizontalScrollButtons = ({ scrollWrapper, }) => {
|
|
2612
|
+
const { t } = useI18n();
|
|
2575
2613
|
const scrollPosition = useHorizontalScrollPosition(scrollWrapper);
|
|
2576
2614
|
const scrollStartClickHandler = () => {
|
|
2577
2615
|
scrollWrapper?.scrollBy({ left: -150, behavior: 'smooth' });
|
|
@@ -2579,9 +2617,10 @@ const HorizontalScrollButtons = ({ scrollWrapper, }) => {
|
|
|
2579
2617
|
const scrollEndClickHandler = () => {
|
|
2580
2618
|
scrollWrapper?.scrollBy({ left: 150, behavior: 'smooth' });
|
|
2581
2619
|
};
|
|
2582
|
-
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" }))] }));
|
|
2620
|
+
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" }))] }));
|
|
2583
2621
|
};
|
|
2584
2622
|
const VerticalScrollButtons = ({ scrollWrapper, }) => {
|
|
2623
|
+
const { t } = useI18n();
|
|
2585
2624
|
const scrollPosition = useVerticalScrollPosition(scrollWrapper);
|
|
2586
2625
|
const scrollTopClickHandler = () => {
|
|
2587
2626
|
scrollWrapper?.scrollBy({ top: -150, behavior: 'smooth' });
|
|
@@ -2589,7 +2628,7 @@ const VerticalScrollButtons = ({ scrollWrapper, }) => {
|
|
|
2589
2628
|
const scrollBottomClickHandler = () => {
|
|
2590
2629
|
scrollWrapper?.scrollBy({ top: 150, behavior: 'smooth' });
|
|
2591
2630
|
};
|
|
2592
|
-
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" }))] }));
|
|
2631
|
+
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" }))] }));
|
|
2593
2632
|
};
|
|
2594
2633
|
|
|
2595
2634
|
const defaultConfiguration = {
|
|
@@ -2731,7 +2770,7 @@ const useInitializeCall = ({ client, callType, callId, handleError, }) => {
|
|
|
2731
2770
|
};
|
|
2732
2771
|
|
|
2733
2772
|
const BlurToggleButton = () => {
|
|
2734
|
-
const { t } =
|
|
2773
|
+
const { t } = useI18n();
|
|
2735
2774
|
const { useCameraState } = videoReactBindings.useCallStateHooks();
|
|
2736
2775
|
const { isMute } = useCameraState();
|
|
2737
2776
|
const { isSupported, isReady, isLoading, backgroundFilter, applyBackgroundBlurFilter, disableBackgroundFilter, } = useBackgroundFilters();
|
|
@@ -2754,44 +2793,59 @@ const BlurToggleButton = () => {
|
|
|
2754
2793
|
]);
|
|
2755
2794
|
const getLabel = () => {
|
|
2756
2795
|
if (isLoading)
|
|
2757
|
-
return t('Applying...');
|
|
2758
|
-
return isBlurred
|
|
2796
|
+
return t('callControls.blurToggleButton.applying.label', 'Applying...');
|
|
2797
|
+
return isBlurred
|
|
2798
|
+
? t('callControls.blurToggleButton.disableBlur.label', 'Disable blur')
|
|
2799
|
+
: t('callControls.blurToggleButton.blurBackground.label', 'Blur background');
|
|
2759
2800
|
};
|
|
2760
2801
|
if (!isSupported)
|
|
2761
2802
|
return null;
|
|
2762
|
-
return (jsxRuntime.jsxs(
|
|
2803
|
+
return (jsxRuntime.jsxs(Button, { variant: "secondary", appearance: "outline", size: "sm", className: "str-video__embedded-blur-toggle", disabled: isDisabled, active: isBlurred, onClick: handleClick, children: [jsxRuntime.jsx(Icon, { icon: "blur-icon" }), jsxRuntime.jsx("span", { children: getLabel() })] }));
|
|
2763
2804
|
};
|
|
2764
2805
|
const CameraMenuWithBlur = () => {
|
|
2765
2806
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(DeviceSelectorVideo, { visualType: "list" }), jsxRuntime.jsx("div", { className: "str-video__embedded-blur-toggle-container", children: jsxRuntime.jsx(BlurToggleButton, {}) })] }));
|
|
2766
2807
|
};
|
|
2767
2808
|
|
|
2809
|
+
const CallDuration = ({ elapsed }) => {
|
|
2810
|
+
if (!elapsed)
|
|
2811
|
+
return null;
|
|
2812
|
+
const secondsAt = elapsed.lastIndexOf(':') + 1;
|
|
2813
|
+
const leading = elapsed.slice(0, secondsAt);
|
|
2814
|
+
const seconds = elapsed.slice(secondsAt);
|
|
2815
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-duration", children: [jsxRuntime.jsx(Icon, { icon: "verified", className: "str-video__embedded-call-duration__icon" }), jsxRuntime.jsxs("span", { className: "str-video__embedded-call-duration__time", children: [jsxRuntime.jsx("span", { className: "str-video__embedded-call-duration__time-leading", children: leading }), seconds] })] }));
|
|
2816
|
+
};
|
|
2817
|
+
|
|
2768
2818
|
const CallEndedScreen = ({ onJoin, onFeedback, }) => {
|
|
2769
|
-
const { t } =
|
|
2770
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__container", children: [jsxRuntime.jsx("h2", { className: "str-video__embedded-call-feedback__title", children: t('Call ended') }), jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__ended-actions", children: [onJoin && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__ended-column", children: [jsxRuntime.jsx("p", { className: "str-video__embedded-call-feedback__ended-label", children: t('Left by mistake?') }), jsxRuntime.jsxs(
|
|
2819
|
+
const { t } = useI18n();
|
|
2820
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__container", children: [jsxRuntime.jsx("h2", { className: "str-video__embedded-call-feedback__title", children: t('callFeedback.callEndedScreen.callEnded.title', 'Call ended') }), jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__ended-actions", children: [onJoin && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__ended-column", children: [jsxRuntime.jsx("p", { className: "str-video__embedded-call-feedback__ended-label", children: t('callFeedback.callEndedScreen.leftByMistake.text', 'Left by mistake?') }), jsxRuntime.jsxs(Button, { variant: "secondary", appearance: "outline", className: "str-video__embedded-call-feedback__ended-button", onClick: onJoin, children: [jsxRuntime.jsx(Icon, { icon: "login" }), t('callFeedback.callEndedScreen.rejoinCall.label', 'Rejoin call')] })] }), jsxRuntime.jsx("div", { className: "str-video__embedded-call-feedback__ended-divider" })] })), jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__ended-column", children: [jsxRuntime.jsx("p", { className: "str-video__embedded-call-feedback__ended-label", children: t('callFeedback.callEndedScreen.helpUsImprove.text', 'Help us improve') }), jsxRuntime.jsxs(Button, { variant: "secondary", appearance: "outline", className: "str-video__embedded-call-feedback__ended-button", onClick: onFeedback, children: [jsxRuntime.jsx(Icon, { icon: "feedback" }), t('callFeedback.callEndedScreen.leaveFeedback.label', 'Leave feedback')] })] })] })] }));
|
|
2771
2821
|
};
|
|
2772
2822
|
|
|
2773
2823
|
const StarRating = ({ value, onChange }) => {
|
|
2774
|
-
const { t } =
|
|
2824
|
+
const { t } = useI18n();
|
|
2775
2825
|
const [hovered, setHovered] = react.useState(0);
|
|
2776
2826
|
const displayValue = hovered || value;
|
|
2777
2827
|
const getStarClasses = (star) => clsx('str-video__embedded-call-feedback__star', star <= displayValue && 'str-video__embedded-call-feedback__star--active');
|
|
2778
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__rating-section", children: [jsxRuntime.jsx("p", { className: "str-video__embedded-call-feedback__rating-label", children: t('How was your call quality?') }), jsxRuntime.jsx("div", { className: "str-video__embedded-call-feedback__stars", onMouseLeave: () => setHovered(0), children: [1, 2, 3, 4, 5].map((star) => (jsxRuntime.jsx("button", { type: "button", className: getStarClasses(star), onClick: () => onChange(star), onMouseEnter: () => setHovered(star), "aria-label": t('
|
|
2828
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__rating-section", children: [jsxRuntime.jsx("p", { className: "str-video__embedded-call-feedback__rating-label", children: t('callFeedback.starRating.howWasCallQuality.text', 'How was your call quality?') }), jsxRuntime.jsx("div", { className: "str-video__embedded-call-feedback__stars", onMouseLeave: () => setHovered(0), children: [1, 2, 3, 4, 5].map((star) => (jsxRuntime.jsx("button", { type: "button", className: getStarClasses(star), onClick: () => onChange(star), onMouseEnter: () => setHovered(star), "aria-label": t('callFeedback.starRating.rateStars.ariaLabel', {
|
|
2829
|
+
count: star,
|
|
2830
|
+
defaultValue_one: 'Rate {{ count }} star',
|
|
2831
|
+
defaultValue_other: 'Rate {{ count }} stars',
|
|
2832
|
+
}), children: jsxRuntime.jsx(Icon, { icon: "star-filled" }) }, star))) })] }));
|
|
2779
2833
|
};
|
|
2780
2834
|
|
|
2781
2835
|
const RatingScreen = ({ onSubmit }) => {
|
|
2782
|
-
const { t } =
|
|
2836
|
+
const { t } = useI18n();
|
|
2783
2837
|
const [rating, setRating] = react.useState(0);
|
|
2784
2838
|
const [message, setMessage] = react.useState('');
|
|
2785
2839
|
const handleSubmit = () => {
|
|
2786
2840
|
if (rating > 0)
|
|
2787
2841
|
onSubmit(rating, message);
|
|
2788
2842
|
};
|
|
2789
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__container", children: [jsxRuntime.jsx("h2", { className: "str-video__embedded-call-feedback__title", children: t('Share your feedback') }), jsxRuntime.jsx(StarRating, { value: rating, onChange: setRating }), jsxRuntime.jsx("textarea", { "aria-label": t('Feedback message'), className: "str-video__embedded-call-feedback__textarea", placeholder: t('Tell us about your experience...'), value: message, onChange: (e) => setMessage(e.target.value), rows: 3 }), jsxRuntime.jsx("div", { className: "str-video__embedded-call-feedback__actions", children: jsxRuntime.jsx(
|
|
2843
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__container", children: [jsxRuntime.jsx("h2", { className: "str-video__embedded-call-feedback__title", children: t('callFeedback.ratingScreen.shareYourFeedback.title', 'Share your feedback') }), jsxRuntime.jsx(StarRating, { value: rating, onChange: setRating }), jsxRuntime.jsx("textarea", { "aria-label": t('callFeedback.ratingScreen.feedbackMessage.ariaLabel', 'Feedback message'), className: "str-video__embedded-call-feedback__textarea", placeholder: t('callFeedback.ratingScreen.tellUsAboutExperience.placeholder', 'Tell us about your experience...'), value: message, onChange: (e) => setMessage(e.target.value), rows: 3 }), jsxRuntime.jsx("div", { className: "str-video__embedded-call-feedback__actions", children: jsxRuntime.jsx(Button, { size: "sm", onClick: handleSubmit, disabled: rating === 0, children: t('callFeedback.ratingScreen.submitFeedback.label', 'Submit feedback') }) })] }));
|
|
2790
2844
|
};
|
|
2791
2845
|
|
|
2792
2846
|
const ThankYouScreen = () => {
|
|
2793
|
-
const { t } =
|
|
2794
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__container", children: [jsxRuntime.jsx("div", { className: "str-video__embedded-call-feedback__checkmark", children: jsxRuntime.jsx(Icon, { icon: "checkmark" }) }), jsxRuntime.jsx("h2", { className: "str-video__embedded-call-feedback__title", children: t('Thank you!') }), jsxRuntime.jsx("p", { className: "str-video__embedded-call-feedback__subtitle", children: t('Your feedback helps improve call quality.') })] }));
|
|
2847
|
+
const { t } = useI18n();
|
|
2848
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-feedback__container", children: [jsxRuntime.jsx("div", { className: "str-video__embedded-call-feedback__checkmark", children: jsxRuntime.jsx(Icon, { icon: "checkmark" }) }), jsxRuntime.jsx("h2", { className: "str-video__embedded-call-feedback__title", children: t('callFeedback.thankYouScreen.thankYou.title', 'Thank you!') }), jsxRuntime.jsx("p", { className: "str-video__embedded-call-feedback__subtitle", children: t('callFeedback.thankYouScreen.feedbackHelpsImprove.text', 'Your feedback helps improve call quality.') })] }));
|
|
2795
2849
|
};
|
|
2796
2850
|
|
|
2797
2851
|
const CallFeedback = ({ onJoin }) => {
|
|
@@ -2820,7 +2874,7 @@ const CallFeedback = ({ onJoin }) => {
|
|
|
2820
2874
|
};
|
|
2821
2875
|
|
|
2822
2876
|
const ConnectionNotification = () => {
|
|
2823
|
-
const { t } =
|
|
2877
|
+
const { t } = useI18n();
|
|
2824
2878
|
const { useCallCallingState } = videoReactBindings.useCallStateHooks();
|
|
2825
2879
|
const callingState = useCallCallingState();
|
|
2826
2880
|
const isOffline = callingState === videoClient.CallingState.OFFLINE;
|
|
@@ -2831,16 +2885,16 @@ const ConnectionNotification = () => {
|
|
|
2831
2885
|
const showError = isOffline || hasFailedToRecover;
|
|
2832
2886
|
const showLoading = isJoining || isReconnecting || isMigrating;
|
|
2833
2887
|
if (showError) {
|
|
2834
|
-
return (jsxRuntime.jsx("div", { className: "str-video__embedded-connection-notification", children: jsxRuntime.jsx(Notification, { isVisible: true, placement: "bottom", message: isOffline
|
|
2835
|
-
? t('You are offline. Check your internet connection.')
|
|
2836
|
-
: t('Failed to restore connection. Please try again.') }) }));
|
|
2888
|
+
return (jsxRuntime.jsx("div", { className: "str-video__embedded-connection-notification", children: jsxRuntime.jsx(Notification, { isVisible: true, state: "error", placement: "bottom", message: isOffline
|
|
2889
|
+
? t('connectionNotification.offline.text', 'You are offline. Check your internet connection.')
|
|
2890
|
+
: t('connectionNotification.failedToRestore.text', 'Failed to restore connection. Please try again.') }) }));
|
|
2837
2891
|
}
|
|
2838
2892
|
if (showLoading) {
|
|
2839
|
-
return (jsxRuntime.jsx("div", { className: "str-video__embedded-connection-notification", children: jsxRuntime.jsx(Notification, { isVisible: true,
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2893
|
+
return (jsxRuntime.jsx("div", { className: "str-video__embedded-connection-notification", children: jsxRuntime.jsx(Notification, { isVisible: true, state: "loading", placement: "bottom", message: isMigrating
|
|
2894
|
+
? t('connectionNotification.migrating.text', 'Migrating...')
|
|
2895
|
+
: isJoining
|
|
2896
|
+
? t('connectionNotification.joining.text', 'Joining')
|
|
2897
|
+
: t('connectionNotification.reconnecting.text', 'Reconnecting...') }) }));
|
|
2844
2898
|
}
|
|
2845
2899
|
return null;
|
|
2846
2900
|
};
|
|
@@ -2864,8 +2918,8 @@ const EmbeddedParticipantViewUI = () => {
|
|
|
2864
2918
|
};
|
|
2865
2919
|
|
|
2866
2920
|
const JoinError = ({ onJoin }) => {
|
|
2867
|
-
const { t } =
|
|
2868
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-join-error", children: [jsxRuntime.jsx("h2", { className: "str-video__embedded-join-error__title", children: t('Failed to join the call') }), jsxRuntime.jsx("p", { className: "str-video__embedded-join-error__message", children: t("We couldn't connect to the server. Please check your connection and try again.") }), jsxRuntime.jsxs(
|
|
2921
|
+
const { t } = useI18n();
|
|
2922
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-join-error", children: [jsxRuntime.jsx("h2", { className: "str-video__embedded-join-error__title", children: t('joinError.failedToJoin.title', 'Failed to join the call') }), jsxRuntime.jsx("p", { className: "str-video__embedded-join-error__message", children: t('joinError.couldNotConnect.text', "We couldn't connect to the server. Please check your connection and try again.") }), jsxRuntime.jsxs(Button, { size: "sm", onClick: onJoin, children: [jsxRuntime.jsx(Icon, { icon: "login" }), t('common.tryAgain.label', 'Try again')] })] }));
|
|
2869
2923
|
};
|
|
2870
2924
|
|
|
2871
2925
|
const ToggleMenuButton$1 = react.forwardRef(function ToggleMenuButtonRender(props, ref) {
|
|
@@ -2875,8 +2929,8 @@ const ToggleMenuButton$1 = react.forwardRef(function ToggleMenuButtonRender(prop
|
|
|
2875
2929
|
?.label || 'Default' }), jsxRuntime.jsx(Icon, { icon: props.menuShown ? 'chevron-down' : 'chevron-up' })] }));
|
|
2876
2930
|
});
|
|
2877
2931
|
const ToggleMicButton = () => {
|
|
2878
|
-
const { t } =
|
|
2879
|
-
return (jsxRuntime.jsxs(MenuToggle, { placement: "top-start", ToggleButton: ToggleMenuButton$1, visualType: MenuVisualType.MENU, children: [jsxRuntime.jsx(DeviceSelectorAudioInput, { visualType: "list", title: t('Microphone') }), jsxRuntime.jsx(DeviceSelectorAudioOutput, { visualType: "list", title: t('Speaker') })] }));
|
|
2932
|
+
const { t } = useI18n();
|
|
2933
|
+
return (jsxRuntime.jsxs(MenuToggle, { placement: "top-start", ToggleButton: ToggleMenuButton$1, visualType: MenuVisualType.MENU, children: [jsxRuntime.jsx(DeviceSelectorAudioInput, { visualType: "list", title: t('common.microphone.label', 'Microphone') }), jsxRuntime.jsx(DeviceSelectorAudioOutput, { visualType: "list", title: t('common.speaker.label', 'Speaker') })] }));
|
|
2880
2934
|
};
|
|
2881
2935
|
|
|
2882
2936
|
const ToggleMenuButton = react.forwardRef(function ToggleMenuButtonRender(props, ref) {
|
|
@@ -2892,48 +2946,49 @@ const ToggleCameraButton = () => {
|
|
|
2892
2946
|
const DisabledDeviceButton = ({ icon, label, }) => (jsxRuntime.jsxs("div", { className: "str-video__embedded-lobby__device-button str-video__embedded-lobby__device-button--disabled", children: [jsxRuntime.jsx(Icon, { className: "str-video__embedded-lobby__device-button-icon", icon: icon }), jsxRuntime.jsx("span", { className: "str-video__embedded-lobby__device-button-label", children: label })] }));
|
|
2893
2947
|
|
|
2894
2948
|
const DisabledVideoPreview = () => {
|
|
2895
|
-
const { t } =
|
|
2949
|
+
const { t } = useI18n();
|
|
2896
2950
|
const user = videoReactBindings.useConnectedUser();
|
|
2897
2951
|
const { useCameraState, useMicrophoneState } = videoReactBindings.useCallStateHooks();
|
|
2898
2952
|
const { hasBrowserPermission: hasCameraPermission } = useCameraState();
|
|
2899
2953
|
const { hasBrowserPermission: hasMicPermission } = useMicrophoneState();
|
|
2900
2954
|
const hasBrowserMediaPermission = hasCameraPermission && hasMicPermission;
|
|
2901
|
-
return (jsxRuntime.jsx("div", { className: "str-video__embedded-lobby__no-permission", children: hasBrowserMediaPermission ? (jsxRuntime.jsx(Avatar, { imageSrc: user?.image, name: user?.name || user?.id })) : (t('Please grant your browser permission to access your camera and microphone.')) }));
|
|
2955
|
+
return (jsxRuntime.jsx("div", { className: "str-video__embedded-lobby__no-permission", children: hasBrowserMediaPermission ? (jsxRuntime.jsx(Avatar, { imageSrc: user?.image, name: user?.name || user?.id })) : (t('lobby.videoPreviewFallbacks.grantBrowserPermission.text', 'Please grant your browser permission to access your camera and microphone.')) }));
|
|
2902
2956
|
};
|
|
2903
2957
|
const NoCameraPreview = () => {
|
|
2904
|
-
const { t } =
|
|
2958
|
+
const { t } = useI18n();
|
|
2905
2959
|
const { useCameraState, useMicrophoneState } = videoReactBindings.useCallStateHooks();
|
|
2906
2960
|
const { hasBrowserPermission: hasCameraPermission } = useCameraState();
|
|
2907
2961
|
const { hasBrowserPermission: hasMicPermission } = useMicrophoneState();
|
|
2908
2962
|
const hasBrowserMediaPermission = hasCameraPermission && hasMicPermission;
|
|
2909
2963
|
if (!hasBrowserMediaPermission) {
|
|
2910
|
-
return (jsxRuntime.jsx("div", { className: "str-video__embedded-lobby__no-permission", children: t('Please grant your browser permission to access your camera and microphone.') }));
|
|
2964
|
+
return (jsxRuntime.jsx("div", { className: "str-video__embedded-lobby__no-permission", children: t('lobby.videoPreviewFallbacks.grantBrowserPermission.text', 'Please grant your browser permission to access your camera and microphone.') }));
|
|
2911
2965
|
}
|
|
2912
|
-
return (jsxRuntime.jsx("div", { className: "str-video__video-preview__no-camera-preview", children: t('No camera found') }));
|
|
2966
|
+
return (jsxRuntime.jsx("div", { className: "str-video__video-preview__no-camera-preview", children: t('common.noCameraFound.text', 'No camera found') }));
|
|
2913
2967
|
};
|
|
2914
2968
|
|
|
2915
2969
|
const DeviceControls = ({ isVideoEnabled }) => {
|
|
2916
|
-
const { t } =
|
|
2970
|
+
const { t } = useI18n();
|
|
2971
|
+
const user = videoReactBindings.useConnectedUser();
|
|
2917
2972
|
const { useCameraState, useMicrophoneState } = videoReactBindings.useCallStateHooks();
|
|
2918
2973
|
const { hasBrowserPermission: hasCameraPermission } = useCameraState();
|
|
2919
2974
|
const { hasBrowserPermission: hasMicPermission } = useMicrophoneState();
|
|
2920
|
-
|
|
2921
|
-
|
|
2975
|
+
const displayName = user?.name || user?.id;
|
|
2976
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "str-video__embedded-lobby__video-preview", children: [jsxRuntime.jsx(VideoPreview, { DisabledVideoPreview: DisabledVideoPreview, NoCameraPreview: NoCameraPreview }), displayName && (jsxRuntime.jsx("span", { className: "str-video__embedded-lobby__participant-label", children: jsxRuntime.jsx("span", { className: "str-video__embedded-lobby__participant-label-text", children: displayName }) })), jsxRuntime.jsxs("div", { className: "str-video__embedded-lobby__media-toggle", children: [jsxRuntime.jsx(ToggleAudioPreviewButton, { Menu: null }), isVideoEnabled && jsxRuntime.jsx(ToggleVideoPreviewButton, { Menu: null })] })] }), jsxRuntime.jsxs("div", { className: "str-video__embedded-lobby__media", children: [hasMicPermission ? (jsxRuntime.jsx(ToggleMicButton, {})) : (jsxRuntime.jsx(DisabledDeviceButton, { icon: "mic", label: t('lobby.deviceControls.permissionNeeded.label', 'Permission needed') })), isVideoEnabled &&
|
|
2977
|
+
(hasCameraPermission ? (jsxRuntime.jsx(ToggleCameraButton, {})) : (jsxRuntime.jsx(DisabledDeviceButton, { icon: "camera", label: t('lobby.deviceControls.permissionNeeded.label', 'Permission needed') })))] })] }));
|
|
2922
2978
|
};
|
|
2923
2979
|
|
|
2924
2980
|
/**
|
|
2925
2981
|
* Lobby component - Device setup screen before joining a call.
|
|
2926
2982
|
*/
|
|
2927
2983
|
const Lobby = ({ onJoin, title, joinLabel }) => {
|
|
2928
|
-
const { t } =
|
|
2929
|
-
const user = videoReactBindings.useConnectedUser();
|
|
2984
|
+
const { t } = useI18n();
|
|
2930
2985
|
const { useCameraState, useCallSettings } = videoReactBindings.useCallStateHooks();
|
|
2931
2986
|
const { isMute } = useCameraState();
|
|
2932
2987
|
const settings = useCallSettings();
|
|
2933
2988
|
const isVideoEnabled = settings?.video.enabled ?? true;
|
|
2934
|
-
const resolvedJoinLabel = joinLabel ?? t('Join');
|
|
2935
|
-
const resolvedTitle = title ?? t('Set up your call before joining');
|
|
2936
|
-
return (jsxRuntime.jsx("div", { className: "str-video__embedded-lobby", children: jsxRuntime.jsxs("div", { className: "str-video__embedded-lobby__content", children: [jsxRuntime.
|
|
2989
|
+
const resolvedJoinLabel = joinLabel ?? t('lobby.join.label', 'Join');
|
|
2990
|
+
const resolvedTitle = title ?? t('lobby.setUpYourCall.title', 'Set up your call before joining');
|
|
2991
|
+
return (jsxRuntime.jsx("div", { className: "str-video__embedded-lobby", children: jsxRuntime.jsxs("div", { className: "str-video__embedded-lobby__content", children: [jsxRuntime.jsxs("div", { className: "str-video__embedded-lobby__title", children: [jsxRuntime.jsx(Icon, { icon: "language", className: "str-video__embedded-lobby__title-icon" }), jsxRuntime.jsx("h1", { className: "str-video__embedded-lobby__heading", children: resolvedTitle })] }), jsxRuntime.jsx("div", { className: clsx('str-video__embedded-lobby__camera', isMute && 'str-video__embedded-lobby__camera--off'), children: jsxRuntime.jsx(DeviceControls, { isVideoEnabled: isVideoEnabled }) }), jsxRuntime.jsxs(Button, { className: "str-video__embedded-lobby__join", onClick: onJoin, children: [jsxRuntime.jsx(Icon, { icon: "login" }), resolvedJoinLabel] })] }) }));
|
|
2937
2992
|
};
|
|
2938
2993
|
|
|
2939
2994
|
const ViewersCount = ({ count }) => (jsxRuntime.jsxs("div", { className: "str-video__embedded-livestream-duration__viewers", children: [jsxRuntime.jsx(Icon, { icon: "eye", className: "str-video__embedded-livestream-duration__eye-icon" }), jsxRuntime.jsx("span", { className: "str-video__embedded-livestream-duration__count", children: videoClient.humanize(count) })] }));
|
|
@@ -3223,12 +3278,12 @@ const EmbeddedClientProvider = ({ apiKey, user, callId, callType, token, tokenPr
|
|
|
3223
3278
|
* Renders the active call control bar
|
|
3224
3279
|
*/
|
|
3225
3280
|
const CallControls = ({ showParticipants, onToggleParticipants, }) => {
|
|
3226
|
-
const { t } =
|
|
3281
|
+
const { t } = useI18n();
|
|
3227
3282
|
const { useCallSession } = videoReactBindings.useCallStateHooks();
|
|
3228
3283
|
const session = useCallSession();
|
|
3229
3284
|
const startedAt = session?.started_at;
|
|
3230
3285
|
const { elapsed } = useCallDuration(startedAt);
|
|
3231
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-controls str-video__call-controls", children: [jsxRuntime.jsxs("div", { className: "str-video__call-controls--group str-video__call-controls--options", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx("div", { className: "str-video__embedded-mobile", children: jsxRuntime.jsx(ReactionsButton, {}) }) }), startedAt && (jsxRuntime.
|
|
3286
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-controls str-video__call-controls", children: [jsxRuntime.jsxs("div", { className: "str-video__call-controls--group str-video__call-controls--options", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx("div", { className: "str-video__embedded-mobile", children: jsxRuntime.jsx(ReactionsButton, {}) }) }), startedAt && (jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(CallDuration, { elapsed: elapsed }) }))] }), jsxRuntime.jsxs("div", { className: "str-video__call-controls--group str-video__call-controls--media", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], hasPermissionsOnly: true, children: jsxRuntime.jsx(MicCaptureErrorNotification, { children: jsxRuntime.jsx(ToggleAudioPublishingButton, { Menu: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(DeviceSelectorAudioInput, { visualType: "list", title: t('common.microphone.label', 'Microphone') }), jsxRuntime.jsx(DeviceSelectorAudioOutput, { visualType: "list", title: t('common.speaker.label', 'Speaker') })] }), menuPlacement: "top" }) }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_VIDEO], hasPermissionsOnly: true, children: jsxRuntime.jsx(ToggleVideoPublishingButton, { Menu: jsxRuntime.jsx(CameraMenuWithBlur, {}), menuPlacement: "top" }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(ReactionsButton, {}) }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SCREENSHARE], children: jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(ScreenShareButton, {}) }) }), jsxRuntime.jsx(RecordCallConfirmationButton, {}), jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(CancelCallConfirmButton, {}) })] }), jsxRuntime.jsx("div", { className: "str-video__call-controls--group str-video__call-controls--sidebar", children: jsxRuntime.jsx(WithTooltip, { title: t('common.participants.label', 'Participants'), children: jsxRuntime.jsx(CompositeButton, { active: showParticipants, "aria-label": t('common.participants.label', 'Participants'), "aria-pressed": showParticipants, onClick: onToggleParticipants, children: jsxRuntime.jsx(Icon, { icon: "participants" }) }) }) })] }));
|
|
3232
3287
|
};
|
|
3233
3288
|
|
|
3234
3289
|
/**
|
|
@@ -3239,7 +3294,7 @@ const CallHeader = () => {
|
|
|
3239
3294
|
const session = useCallSession();
|
|
3240
3295
|
const startedAt = session?.started_at;
|
|
3241
3296
|
const { elapsed } = useCallDuration(startedAt);
|
|
3242
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-header", children: [startedAt &&
|
|
3297
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call-header", children: [startedAt && jsxRuntime.jsx(CallDuration, { elapsed: elapsed }), jsxRuntime.jsx(CancelCallConfirmButton, {})] }));
|
|
3243
3298
|
};
|
|
3244
3299
|
|
|
3245
3300
|
/**
|
|
@@ -3252,7 +3307,7 @@ const CallLayout = () => {
|
|
|
3252
3307
|
const handleToggleParticipants = react.useCallback(() => {
|
|
3253
3308
|
setShowParticipants((prev) => !prev);
|
|
3254
3309
|
}, []);
|
|
3255
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call", children: [jsxRuntime.jsx(ConnectionNotification, {}), jsxRuntime.jsx(PermissionRequests, {}), jsxRuntime.jsx("div", { className: "str-video__embedded-notifications", children: jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], hasPermissionsOnly: true, children: jsxRuntime.jsx(SpeakingWhileMutedNotification, {}) }) }), jsxRuntime.jsx(CallHeader, {}), jsxRuntime.jsxs("div", { className: "str-video__embedded-layout", children: [jsxRuntime.jsx("div", { className: "str-video__embedded-layout__stage", children: jsxRuntime.jsx(LayoutComponent, { ...layoutProps }) }), jsxRuntime.jsx("div", { className: clsx('str-video__embedded-sidebar', showParticipants && 'str-video__embedded-sidebar--open'), children: showParticipants && (jsxRuntime.jsx("div", { className: "str-video__embedded-participants", children: jsxRuntime.jsx(CallParticipantsList, { onClose: handleToggleParticipants }) })) })] }), jsxRuntime.jsx(CallControls, { showParticipants: showParticipants, onToggleParticipants: handleToggleParticipants })] }));
|
|
3310
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call", children: [jsxRuntime.jsx(ConnectionNotification, {}), jsxRuntime.jsx(PermissionRequests, {}), jsxRuntime.jsx("div", { className: "str-video__embedded-notifications", children: jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], hasPermissionsOnly: true, children: jsxRuntime.jsx(SpeakingWhileMutedNotification, { placement: "top" }) }) }), jsxRuntime.jsx(CallHeader, {}), jsxRuntime.jsxs("div", { className: "str-video__embedded-layout", children: [jsxRuntime.jsx("div", { className: "str-video__embedded-layout__stage", children: jsxRuntime.jsx(LayoutComponent, { ...layoutProps }) }), jsxRuntime.jsx("div", { className: clsx('str-video__embedded-sidebar', showParticipants && 'str-video__embedded-sidebar--open'), children: showParticipants && (jsxRuntime.jsx("div", { className: "str-video__embedded-participants", children: jsxRuntime.jsx(CallParticipantsList, { onClose: handleToggleParticipants }) })) })] }), jsxRuntime.jsx(CallControls, { showParticipants: showParticipants, onToggleParticipants: handleToggleParticipants })] }));
|
|
3256
3311
|
};
|
|
3257
3312
|
|
|
3258
3313
|
/**
|
|
@@ -3302,7 +3357,7 @@ const CallStateRouter = () => {
|
|
|
3302
3357
|
const EmbeddedCall = ({ children, ...props }) => (jsxRuntime.jsxs(EmbeddedClientProvider, { ...props, children: [jsxRuntime.jsx(CallStateRouter, {}), children] }));
|
|
3303
3358
|
|
|
3304
3359
|
const HostLayout = ({ isLive, isBackstageEnabled, onGoLive, onStopLive, }) => {
|
|
3305
|
-
const { t } =
|
|
3360
|
+
const { t } = useI18n();
|
|
3306
3361
|
const { useParticipantCount, useCallSession } = videoReactBindings.useCallStateHooks();
|
|
3307
3362
|
const participantCount = useParticipantCount();
|
|
3308
3363
|
const session = useCallSession();
|
|
@@ -3317,13 +3372,15 @@ const HostLayout = ({ isLive, isBackstageEnabled, onGoLive, onStopLive, }) => {
|
|
|
3317
3372
|
}, []);
|
|
3318
3373
|
const livestreamStatus = (jsxRuntime.jsxs("div", { className: "str-video__embedded-livestream-duration", "aria-live": "polite", "aria-atomic": "true", children: [jsxRuntime.jsx("span", { className: isLive
|
|
3319
3374
|
? 'str-video__embedded-livestream-duration__live-badge'
|
|
3320
|
-
: 'str-video__embedded-livestream-duration__backstage-badge', children: isLive
|
|
3321
|
-
|
|
3375
|
+
: 'str-video__embedded-livestream-duration__backstage-badge', children: isLive
|
|
3376
|
+
? t('common.live.label', 'Live')
|
|
3377
|
+
: t('livestreamHost.backstage.text', 'Backstage') }), jsxRuntime.jsx(ViewersCount, { count: participantCount }), isLive && elapsed && (jsxRuntime.jsx("span", { className: "str-video__embedded-livestream-duration__elapsed", children: elapsed }))] }));
|
|
3378
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call str-video__embedded-livestream", children: [jsxRuntime.jsx(ConnectionNotification, {}), jsxRuntime.jsx(PermissionRequests, {}), jsxRuntime.jsxs("div", { className: "str-video__embedded-call-header", children: [livestreamStatus, jsxRuntime.jsx(CancelCallConfirmButton, {})] }), jsxRuntime.jsxs("div", { className: "str-video__embedded-layout", children: [jsxRuntime.jsx("div", { className: "str-video__embedded-layout__stage", children: jsxRuntime.jsx(LayoutComponent, { ...layoutProps }) }), jsxRuntime.jsx("div", { className: clsx('str-video__embedded-sidebar', showParticipants && 'str-video__embedded-sidebar--open'), children: showParticipants && (jsxRuntime.jsx("div", { className: "str-video__embedded-participants", children: jsxRuntime.jsx(CallParticipantsList, { onClose: handleCloseParticipants }) })) })] }), jsxRuntime.jsxs("div", { className: "str-video__embedded-call-controls str-video__call-controls", children: [jsxRuntime.jsxs("div", { className: "str-video__call-controls--group str-video__call-controls--options", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx("div", { className: "str-video__embedded-mobile", children: jsxRuntime.jsx(ReactionsButton, {}) }) }), jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: livestreamStatus })] }), jsxRuntime.jsxs("div", { className: "str-video__call-controls--group str-video__call-controls--media", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], hasPermissionsOnly: true, children: jsxRuntime.jsx(MicCaptureErrorNotification, { children: jsxRuntime.jsx(ToggleAudioPublishingButton, { Menu: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(DeviceSelectorAudioOutput, { visualType: "list", title: t('common.speaker.label', 'Speaker') }), jsxRuntime.jsx(DeviceSelectorAudioInput, { visualType: "list", title: t('common.microphone.label', 'Microphone') })] }), menuPlacement: "top" }) }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_VIDEO], hasPermissionsOnly: true, children: jsxRuntime.jsx(ToggleVideoPublishingButton, { Menu: jsxRuntime.jsx(CameraMenuWithBlur, {}), menuPlacement: "top" }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(ReactionsButton, {}) }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SCREENSHARE], children: jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(ScreenShareButton, {}) }) }), jsxRuntime.jsx(RecordCallConfirmationButton, {}), isBackstageEnabled && (jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.UPDATE_CALL], children: isLive ? (jsxRuntime.jsx(WithTooltip, { title: t('livestreamHost.endStream.title', 'End Stream'), children: jsxRuntime.jsxs(Button, { variant: "secondary", size: "sm", className: "str-video__embedded-end-stream-button", onClick: onStopLive, children: [jsxRuntime.jsx(Icon, { icon: "call-end" }), jsxRuntime.jsx("span", { children: t('livestreamHost.endLive.label', 'End Live') })] }) })) : (jsxRuntime.jsx(WithTooltip, { title: t('livestreamHost.startStream.title', 'Start Stream'), children: jsxRuntime.jsxs(Button, { variant: "primary", size: "sm", className: "str-video__embedded-go-live-button", onClick: onGoLive, children: [jsxRuntime.jsx(Icon, { icon: "streaming" }), jsxRuntime.jsx("span", { children: t('livestreamHost.goLive.label', 'Go Live') })] }) })) })), jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(CancelCallConfirmButton, {}) })] }), jsxRuntime.jsx("div", { className: "str-video__call-controls--group str-video__call-controls--sidebar", children: jsxRuntime.jsx(WithTooltip, { title: t('common.participants.label', 'Participants'), children: jsxRuntime.jsx(CompositeButton, { active: showParticipants, "aria-label": t('common.participants.label', 'Participants'), "aria-pressed": showParticipants, onClick: handleToggleParticipants, children: jsxRuntime.jsx(Icon, { icon: "participants" }) }) }) })] })] }));
|
|
3322
3379
|
};
|
|
3323
3380
|
|
|
3324
3381
|
const HostStateRouter = () => {
|
|
3325
3382
|
const call = videoReactBindings.useCall();
|
|
3326
|
-
const { t } =
|
|
3383
|
+
const { t } = useI18n();
|
|
3327
3384
|
const { onError } = useEmbeddedConfiguration();
|
|
3328
3385
|
const { useCallCallingState, useIsCallLive, useCallSettings, useLocalParticipant, } = videoReactBindings.useCallStateHooks();
|
|
3329
3386
|
const callingState = useCallCallingState();
|
|
@@ -3372,8 +3429,10 @@ const HostStateRouter = () => {
|
|
|
3372
3429
|
if (callingState === videoClient.CallingState.IDLE ||
|
|
3373
3430
|
callingState === videoClient.CallingState.UNKNOWN) {
|
|
3374
3431
|
return (jsxRuntime.jsx(Lobby, { onJoin: handleJoin, title: isBackstageEnabled
|
|
3375
|
-
? t('Prepare your livestream')
|
|
3376
|
-
: t('Ready to go live'), joinLabel: isBackstageEnabled
|
|
3432
|
+
? t('livestreamHost.prepareLivestream.title', 'Prepare your livestream')
|
|
3433
|
+
: t('livestreamHost.readyToGoLive.title', 'Ready to go live'), joinLabel: isBackstageEnabled
|
|
3434
|
+
? t('livestreamHost.enterBackstage.label', 'Enter Backstage')
|
|
3435
|
+
: t('livestreamHost.goLive.label', 'Go Live') }));
|
|
3377
3436
|
}
|
|
3378
3437
|
if (callingState === videoClient.CallingState.JOINING && !localParticipant) {
|
|
3379
3438
|
return jsxRuntime.jsx(LoadingIndicator, { className: "str-video__embedded-loading" });
|
|
@@ -3392,7 +3451,7 @@ const checkCanJoinEarly = (startsAt, joinAheadTimeSeconds) => {
|
|
|
3392
3451
|
return now >= earliestJoin && now < +startsAt;
|
|
3393
3452
|
};
|
|
3394
3453
|
const ViewerLobby = ({ onJoin }) => {
|
|
3395
|
-
const { t } =
|
|
3454
|
+
const { t } = useI18n();
|
|
3396
3455
|
const { useCallStartsAt, useCallEndedAt, useHasPermissions, useParticipantCount, useIsCallLive, useCallSettings, } = videoReactBindings.useCallStateHooks();
|
|
3397
3456
|
const startsAt = useCallStartsAt();
|
|
3398
3457
|
const endedAt = useCallEndedAt();
|
|
@@ -3433,9 +3492,9 @@ const ViewerLobby = ({ onJoin }) => {
|
|
|
3433
3492
|
if (!startsAt)
|
|
3434
3493
|
return null;
|
|
3435
3494
|
if (startsAtPassed) {
|
|
3436
|
-
return t('Livestream starts soon');
|
|
3495
|
+
return t('livestream.backstage.startsSoon.text', 'Livestream starts soon');
|
|
3437
3496
|
}
|
|
3438
|
-
return t('Livestream starts at {{ time }}', {
|
|
3497
|
+
return t('livestream.backstage.startsAt.text', 'Livestream starts at {{ time }}', {
|
|
3439
3498
|
time: startsAt.toLocaleTimeString([], {
|
|
3440
3499
|
hour: '2-digit',
|
|
3441
3500
|
minute: '2-digit',
|
|
@@ -3443,13 +3502,13 @@ const ViewerLobby = ({ onJoin }) => {
|
|
|
3443
3502
|
});
|
|
3444
3503
|
};
|
|
3445
3504
|
return (jsxRuntime.jsx("div", { className: "str-video__embedded-viewer-lobby", children: jsxRuntime.jsxs("div", { className: "str-video__embedded-viewer-lobby__content", children: [jsxRuntime.jsx("div", { className: "str-video__embedded-viewer-lobby__icon", children: jsxRuntime.jsx(Icon, { icon: "streaming" }) }), jsxRuntime.jsx("h2", { className: "str-video__embedded-viewer-lobby__title", children: canJoin
|
|
3446
|
-
? t('Stream is ready!')
|
|
3447
|
-
: t('Waiting for the livestream to start') }), !canJoin && getStartsAtMessage() && (jsxRuntime.jsx("p", { className: "str-video__embedded-viewer-lobby__starts-at", children: getStartsAtMessage() })), participantCount > 0 && jsxRuntime.jsx(ViewersCount, { count: participantCount }), jsxRuntime.jsx("div", { className: "str-video__embedded-viewer-lobby__actions", children: canJoin ? (jsxRuntime.jsx(
|
|
3505
|
+
? t('livestreamViewer.lobby.streamReady.title', 'Stream is ready!')
|
|
3506
|
+
: t('livestreamViewer.lobby.waitingForStart.title', 'Waiting for the livestream to start') }), !canJoin && getStartsAtMessage() && (jsxRuntime.jsx("p", { className: "str-video__embedded-viewer-lobby__starts-at", children: getStartsAtMessage() })), participantCount > 0 && jsxRuntime.jsx(ViewersCount, { count: participantCount }), jsxRuntime.jsx("div", { className: "str-video__embedded-viewer-lobby__actions", children: canJoin ? (jsxRuntime.jsx(Button, { size: "sm", onClick: onJoin, children: t('livestreamViewer.lobby.joinStream.label', 'Join Stream') })) : (jsxRuntime.jsxs("label", { className: "str-video__embedded-viewer-lobby__auto-join", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: autoJoin, onChange: (e) => setAutoJoin(e.target.checked) }), jsxRuntime.jsx("span", { children: t('livestreamViewer.lobby.joinAutomatically.text', 'Join automatically when stream starts') })] })) })] }) }));
|
|
3448
3507
|
};
|
|
3449
3508
|
|
|
3450
3509
|
const ViewerLayout = () => {
|
|
3451
3510
|
useWakeLock();
|
|
3452
|
-
const { t } =
|
|
3511
|
+
const { t } = useI18n();
|
|
3453
3512
|
const { useParticipantCount, useCallSession } = videoReactBindings.useCallStateHooks();
|
|
3454
3513
|
const participantCount = useParticipantCount();
|
|
3455
3514
|
const session = useCallSession();
|
|
@@ -3462,7 +3521,7 @@ const ViewerLayout = () => {
|
|
|
3462
3521
|
const handleToggleParticipants = react.useCallback(() => {
|
|
3463
3522
|
setShowParticipants((prev) => !prev);
|
|
3464
3523
|
}, []);
|
|
3465
|
-
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call str-video__embedded-livestream", children: [jsxRuntime.jsx(ConnectionNotification, {}), jsxRuntime.jsxs("div", { className: "str-video__embedded-call-header", children: [jsxRuntime.jsxs("div", { className: "str-video__embedded-livestream-duration", children: [jsxRuntime.jsx("span", { className: "str-video__embedded-livestream-duration__live-badge", children: t('Live') }), jsxRuntime.jsx(ViewersCount, { count: participantCount }), elapsed && (jsxRuntime.jsx("span", { className: "str-video__embedded-livestream-duration__elapsed", children: elapsed }))] }), jsxRuntime.jsx(CancelCallConfirmButton, {})] }), jsxRuntime.jsxs("div", { className: "str-video__embedded-layout", children: [jsxRuntime.jsx("div", { className: "str-video__embedded-layout__stage", children: jsxRuntime.jsx(LayoutComponent, { ...layoutProps }) }), jsxRuntime.jsx("div", { className: clsx('str-video__embedded-sidebar', showParticipants && 'str-video__embedded-sidebar--open'), children: showParticipants && (jsxRuntime.jsx("div", { className: "str-video__embedded-participants", children: jsxRuntime.jsx(CallParticipantsList, { onClose: handleCloseParticipants }) })) })] }), jsxRuntime.jsxs("div", { className: "str-video__embedded-call-controls str-video__call-controls", children: [jsxRuntime.jsxs("div", { className: "str-video__call-controls--group str-video__call-controls--options", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx("div", { className: "str-video__embedded-mobile", children: jsxRuntime.jsx(ReactionsButton, {}) }) }), jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsxs("div", { className: "str-video__embedded-livestream-duration", children: [jsxRuntime.jsx("span", { className: "str-video__embedded-livestream-duration__live-badge", children: t('Live') }), jsxRuntime.jsx(ViewersCount, { count: participantCount }), elapsed && (jsxRuntime.jsx("span", { className: "str-video__embedded-livestream-duration__elapsed", children: elapsed }))] }) })] }), jsxRuntime.jsxs("div", { className: "str-video__call-controls--group str-video__call-controls--media", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], hasPermissionsOnly: true, children: jsxRuntime.jsx(MicCaptureErrorNotification, { children: jsxRuntime.jsx(ToggleAudioPublishingButton, { Menu: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(DeviceSelectorAudioOutput, { visualType: "list", title: t('Speaker') }), jsxRuntime.jsx(DeviceSelectorAudioInput, { visualType: "list", title: t('Microphone') })] }), menuPlacement: "top" }) }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_VIDEO], hasPermissionsOnly: true, children: jsxRuntime.jsx(ToggleVideoPublishingButton, { Menu: jsxRuntime.jsx(CameraMenuWithBlur, {}), menuPlacement: "top" }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(ReactionsButton, {}) }) }), jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(CancelCallConfirmButton, {}) })] }), jsxRuntime.jsx("div", { className: "str-video__call-controls--group str-video__call-controls--sidebar", children: jsxRuntime.jsx(WithTooltip, { title: t('Participants'), children: jsxRuntime.jsx(CompositeButton, { active: showParticipants, "aria-label": t('Participants'), "aria-pressed": showParticipants, onClick: handleToggleParticipants, children: jsxRuntime.jsx(Icon, { icon: "participants" }) }) }) })] })] }));
|
|
3524
|
+
return (jsxRuntime.jsxs("div", { className: "str-video__embedded-call str-video__embedded-livestream", children: [jsxRuntime.jsx(ConnectionNotification, {}), jsxRuntime.jsxs("div", { className: "str-video__embedded-call-header", children: [jsxRuntime.jsxs("div", { className: "str-video__embedded-livestream-duration", children: [jsxRuntime.jsx("span", { className: "str-video__embedded-livestream-duration__live-badge", children: t('common.live.label', 'Live') }), jsxRuntime.jsx(ViewersCount, { count: participantCount }), elapsed && (jsxRuntime.jsx("span", { className: "str-video__embedded-livestream-duration__elapsed", children: elapsed }))] }), jsxRuntime.jsx(CancelCallConfirmButton, {})] }), jsxRuntime.jsxs("div", { className: "str-video__embedded-layout", children: [jsxRuntime.jsx("div", { className: "str-video__embedded-layout__stage", children: jsxRuntime.jsx(LayoutComponent, { ...layoutProps }) }), jsxRuntime.jsx("div", { className: clsx('str-video__embedded-sidebar', showParticipants && 'str-video__embedded-sidebar--open'), children: showParticipants && (jsxRuntime.jsx("div", { className: "str-video__embedded-participants", children: jsxRuntime.jsx(CallParticipantsList, { onClose: handleCloseParticipants }) })) })] }), jsxRuntime.jsxs("div", { className: "str-video__embedded-call-controls str-video__call-controls", children: [jsxRuntime.jsxs("div", { className: "str-video__call-controls--group str-video__call-controls--options", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx("div", { className: "str-video__embedded-mobile", children: jsxRuntime.jsx(ReactionsButton, {}) }) }), jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsxs("div", { className: "str-video__embedded-livestream-duration", children: [jsxRuntime.jsx("span", { className: "str-video__embedded-livestream-duration__live-badge", children: t('common.live.label', 'Live') }), jsxRuntime.jsx(ViewersCount, { count: participantCount }), elapsed && (jsxRuntime.jsx("span", { className: "str-video__embedded-livestream-duration__elapsed", children: elapsed }))] }) })] }), jsxRuntime.jsxs("div", { className: "str-video__call-controls--group str-video__call-controls--media", children: [jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_AUDIO], hasPermissionsOnly: true, children: jsxRuntime.jsx(MicCaptureErrorNotification, { children: jsxRuntime.jsx(ToggleAudioPublishingButton, { Menu: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(DeviceSelectorAudioOutput, { visualType: "list", title: t('common.speaker.label', 'Speaker') }), jsxRuntime.jsx(DeviceSelectorAudioInput, { visualType: "list", title: t('common.microphone.label', 'Microphone') })] }), menuPlacement: "top" }) }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.SEND_VIDEO], hasPermissionsOnly: true, children: jsxRuntime.jsx(ToggleVideoPublishingButton, { Menu: jsxRuntime.jsx(CameraMenuWithBlur, {}), menuPlacement: "top" }) }), jsxRuntime.jsx(videoReactBindings.Restricted, { requiredGrants: [videoClient.OwnCapability.CREATE_REACTION], children: jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(ReactionsButton, {}) }) }), jsxRuntime.jsx("div", { className: "str-video__embedded-desktop", children: jsxRuntime.jsx(CancelCallConfirmButton, {}) })] }), jsxRuntime.jsx("div", { className: "str-video__call-controls--group str-video__call-controls--sidebar", children: jsxRuntime.jsx(WithTooltip, { title: t('common.participants.label', 'Participants'), children: jsxRuntime.jsx(CompositeButton, { active: showParticipants, "aria-label": t('common.participants.label', 'Participants'), "aria-pressed": showParticipants, onClick: handleToggleParticipants, children: jsxRuntime.jsx(Icon, { icon: "participants" }) }) }) })] })] }));
|
|
3466
3525
|
};
|
|
3467
3526
|
|
|
3468
3527
|
const ViewerStateRouter = () => {
|