@stream-io/video-react-sdk 1.40.2 → 1.42.0
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 +33 -4
- package/dist/embedded.cjs.js +4 -4
- package/dist/embedded.cjs.js.map +1 -1
- package/dist/esm/embedded.js +3 -0
- package/dist/esm/embedded.js.map +1 -0
- package/dist/esm/index.js +92 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/src/components/Avatar/Avatar.js +14 -0
- package/dist/esm/src/components/Avatar/Avatar.js.map +1 -0
- package/dist/{background-filters-D2U5UBbH.es.js → esm/src/components/BackgroundFilters/BackgroundFilters.js} +1 -1
- package/dist/esm/src/components/BackgroundFilters/BackgroundFilters.js.map +1 -0
- package/dist/esm/src/components/BackgroundFilters/BackgroundFiltersProvider.js +33 -0
- package/dist/esm/src/components/BackgroundFilters/BackgroundFiltersProvider.js.map +1 -0
- package/dist/esm/src/components/Button/CompositeButton.js +29 -0
- package/dist/esm/src/components/Button/CompositeButton.js.map +1 -0
- package/dist/esm/src/components/Button/IconButton.js +18 -0
- package/dist/esm/src/components/Button/IconButton.js.map +1 -0
- package/dist/esm/src/components/Button/TextButton.js +8 -0
- package/dist/esm/src/components/Button/TextButton.js.map +1 -0
- package/dist/esm/src/components/CallControls/AcceptCallButton.js +28 -0
- package/dist/esm/src/components/CallControls/AcceptCallButton.js.map +1 -0
- package/dist/esm/src/components/CallControls/CallControls.js +21 -0
- package/dist/esm/src/components/CallControls/CallControls.js.map +1 -0
- package/dist/esm/src/components/CallControls/CallStatsButton.js +18 -0
- package/dist/esm/src/components/CallControls/CallStatsButton.js.map +1 -0
- package/dist/esm/src/components/CallControls/CancelCallButton.js +78 -0
- package/dist/esm/src/components/CallControls/CancelCallButton.js.map +1 -0
- package/dist/esm/src/components/CallControls/ReactionsButton.js +61 -0
- package/dist/esm/src/components/CallControls/ReactionsButton.js.map +1 -0
- package/dist/esm/src/components/CallControls/RecordCallButton.js +64 -0
- package/dist/esm/src/components/CallControls/RecordCallButton.js.map +1 -0
- package/dist/esm/src/components/CallControls/ScreenShareButton.js +44 -0
- package/dist/esm/src/components/CallControls/ScreenShareButton.js.map +1 -0
- package/dist/esm/src/components/CallControls/ToggleAudioButton.js +72 -0
- package/dist/esm/src/components/CallControls/ToggleAudioButton.js.map +1 -0
- package/dist/esm/src/components/CallControls/ToggleAudioOutputButton.js +27 -0
- package/dist/esm/src/components/CallControls/ToggleAudioOutputButton.js.map +1 -0
- package/dist/esm/src/components/CallControls/ToggleVideoButton.js +81 -0
- package/dist/esm/src/components/CallControls/ToggleVideoButton.js.map +1 -0
- package/dist/esm/src/components/CallParticipantsList/BlockedUserListing.js +23 -0
- package/dist/esm/src/components/CallParticipantsList/BlockedUserListing.js.map +1 -0
- package/dist/esm/src/components/CallParticipantsList/CallParticipantListHeader.js +15 -0
- package/dist/esm/src/components/CallParticipantsList/CallParticipantListHeader.js.map +1 -0
- package/dist/esm/src/components/CallParticipantsList/CallParticipantListing.js +7 -0
- package/dist/esm/src/components/CallParticipantsList/CallParticipantListing.js.map +1 -0
- package/dist/esm/src/components/CallParticipantsList/CallParticipantListingItem.js +46 -0
- package/dist/esm/src/components/CallParticipantsList/CallParticipantListingItem.js.map +1 -0
- package/dist/esm/src/components/CallParticipantsList/CallParticipantsList.js +81 -0
- package/dist/esm/src/components/CallParticipantsList/CallParticipantsList.js.map +1 -0
- package/dist/esm/src/components/CallParticipantsList/EmptyParticipantSearchList.js +10 -0
- package/dist/esm/src/components/CallParticipantsList/EmptyParticipantSearchList.js.map +1 -0
- package/dist/esm/src/components/CallPreview/CallPreview.js +24 -0
- package/dist/esm/src/components/CallPreview/CallPreview.js.map +1 -0
- package/dist/esm/src/components/CallRecordingList/CallRecordingList.js +12 -0
- package/dist/esm/src/components/CallRecordingList/CallRecordingList.js.map +1 -0
- package/dist/esm/src/components/CallRecordingList/CallRecordingListHeader.js +12 -0
- package/dist/esm/src/components/CallRecordingList/CallRecordingListHeader.js.map +1 -0
- package/dist/esm/src/components/CallRecordingList/CallRecordingListItem.js +14 -0
- package/dist/esm/src/components/CallRecordingList/CallRecordingListItem.js.map +1 -0
- package/dist/esm/src/components/CallRecordingList/EmptyCallRecordingListing.js +8 -0
- package/dist/esm/src/components/CallRecordingList/EmptyCallRecordingListing.js.map +1 -0
- package/dist/esm/src/components/CallRecordingList/LoadingCallRecordingListing.js +10 -0
- package/dist/esm/src/components/CallRecordingList/LoadingCallRecordingListing.js.map +1 -0
- package/dist/esm/src/components/CallStats/CallStats.js +180 -0
- package/dist/esm/src/components/CallStats/CallStats.js.map +1 -0
- package/dist/{latency-chart-Bj5OSYzg.es.js → esm/src/components/CallStats/CallStatsLatencyChart.js} +1 -1
- package/dist/esm/src/components/CallStats/CallStatsLatencyChart.js.map +1 -0
- package/dist/esm/src/components/DeviceSettings/AudioVolumeIndicator.js +27 -0
- package/dist/esm/src/components/DeviceSettings/AudioVolumeIndicator.js.map +1 -0
- package/dist/esm/src/components/DeviceSettings/DeviceAudioPreviewItem.js +42 -0
- package/dist/esm/src/components/DeviceSettings/DeviceAudioPreviewItem.js.map +1 -0
- package/dist/esm/src/components/DeviceSettings/DeviceSelector.js +67 -0
- package/dist/esm/src/components/DeviceSettings/DeviceSelector.js.map +1 -0
- package/dist/esm/src/components/DeviceSettings/DeviceSelectorAudio.js +26 -0
- package/dist/esm/src/components/DeviceSettings/DeviceSelectorAudio.js.map +1 -0
- package/dist/esm/src/components/DeviceSettings/DeviceSelectorVideo.js +15 -0
- package/dist/esm/src/components/DeviceSettings/DeviceSelectorVideo.js.map +1 -0
- package/dist/esm/src/components/DeviceSettings/DeviceSettings.js +26 -0
- package/dist/esm/src/components/DeviceSettings/DeviceSettings.js.map +1 -0
- package/dist/esm/src/components/DeviceSettings/DeviceVideoPreviewItem.js +42 -0
- package/dist/esm/src/components/DeviceSettings/DeviceVideoPreviewItem.js.map +1 -0
- package/dist/esm/src/components/DeviceSettings/SpeakerTest.js +57 -0
- package/dist/esm/src/components/DeviceSettings/SpeakerTest.js.map +1 -0
- package/dist/esm/src/components/DropdownSelect/DropdownSelect.js +79 -0
- package/dist/esm/src/components/DropdownSelect/DropdownSelect.js.map +1 -0
- package/dist/esm/src/components/Icon/Icon.js +7 -0
- package/dist/esm/src/components/Icon/Icon.js.map +1 -0
- package/dist/esm/src/components/LoadingIndicator/LoadingIndicator.js +9 -0
- package/dist/esm/src/components/LoadingIndicator/LoadingIndicator.js.map +1 -0
- package/dist/esm/src/components/Menu/GenericMenu.js +19 -0
- package/dist/esm/src/components/Menu/GenericMenu.js.map +1 -0
- package/dist/esm/src/components/Menu/MenuToggle.js +75 -0
- package/dist/esm/src/components/Menu/MenuToggle.js.map +1 -0
- package/dist/esm/src/components/NoiseCancellation/NoiseCancellationProvider.js +96 -0
- package/dist/esm/src/components/NoiseCancellation/NoiseCancellationProvider.js.map +1 -0
- package/dist/esm/src/components/Notification/MicCaptureErrorNotification.js +23 -0
- package/dist/esm/src/components/Notification/MicCaptureErrorNotification.js.map +1 -0
- package/dist/esm/src/components/Notification/Notification.js +31 -0
- package/dist/esm/src/components/Notification/Notification.js.map +1 -0
- package/dist/esm/src/components/Notification/PermissionNotification.js +32 -0
- package/dist/esm/src/components/Notification/PermissionNotification.js.map +1 -0
- package/dist/esm/src/components/Notification/RecordingInProgressNotification.js +23 -0
- package/dist/esm/src/components/Notification/RecordingInProgressNotification.js.map +1 -0
- package/dist/esm/src/components/Notification/SpeakingWhileMutedNotification.js +14 -0
- package/dist/esm/src/components/Notification/SpeakingWhileMutedNotification.js.map +1 -0
- package/dist/esm/src/components/Permissions/PermissionRequests.js +99 -0
- package/dist/esm/src/components/Permissions/PermissionRequests.js.map +1 -0
- package/dist/esm/src/components/Reaction/Reaction.js +32 -0
- package/dist/esm/src/components/Reaction/Reaction.js.map +1 -0
- package/dist/esm/src/components/RingingCall/RingingCall.js +48 -0
- package/dist/esm/src/components/RingingCall/RingingCall.js.map +1 -0
- package/dist/esm/src/components/RingingCall/RingingCallControls.js +34 -0
- package/dist/esm/src/components/RingingCall/RingingCallControls.js.map +1 -0
- package/dist/esm/src/components/Search/SearchInput.js +27 -0
- package/dist/esm/src/components/Search/SearchInput.js.map +1 -0
- package/dist/esm/src/components/Search/SearchResults.js +15 -0
- package/dist/esm/src/components/Search/SearchResults.js.map +1 -0
- package/dist/esm/src/components/Search/hooks/useSearch.js +38 -0
- package/dist/esm/src/components/Search/hooks/useSearch.js.map +1 -0
- package/dist/esm/src/components/StreamTheme/StreamTheme.js +9 -0
- package/dist/esm/src/components/StreamTheme/StreamTheme.js.map +1 -0
- package/dist/esm/src/components/Tooltip/Tooltip.js +29 -0
- package/dist/esm/src/components/Tooltip/Tooltip.js.map +1 -0
- package/dist/esm/src/components/Tooltip/WithTooltip.js +15 -0
- package/dist/esm/src/components/Tooltip/WithTooltip.js.map +1 -0
- package/dist/esm/src/components/Tooltip/hooks/useEnterLeaveHandlers.js +17 -0
- package/dist/esm/src/components/Tooltip/hooks/useEnterLeaveHandlers.js.map +1 -0
- package/dist/esm/src/components/VideoPreview/VideoPreview.js +37 -0
- package/dist/esm/src/components/VideoPreview/VideoPreview.js.map +1 -0
- package/dist/esm/src/core/components/Audio/Audio.js +22 -0
- package/dist/esm/src/core/components/Audio/Audio.js.map +1 -0
- package/dist/esm/src/core/components/Audio/ParticipantsAudio.js +23 -0
- package/dist/esm/src/core/components/Audio/ParticipantsAudio.js.map +1 -0
- package/dist/esm/src/core/components/CallLayout/LivestreamLayout.js +150 -0
- package/dist/esm/src/core/components/CallLayout/LivestreamLayout.js.map +1 -0
- package/dist/esm/src/core/components/CallLayout/PaginatedGridLayout.js +79 -0
- package/dist/esm/src/core/components/CallLayout/PaginatedGridLayout.js.map +1 -0
- package/dist/esm/src/core/components/CallLayout/PipLayout/Grid.js +80 -0
- package/dist/esm/src/core/components/CallLayout/PipLayout/Grid.js.map +1 -0
- package/dist/esm/src/core/components/CallLayout/PipLayout/Host.js +13 -0
- package/dist/esm/src/core/components/CallLayout/PipLayout/Host.js.map +1 -0
- package/dist/esm/src/core/components/CallLayout/PipLayout/Pip.js +57 -0
- package/dist/esm/src/core/components/CallLayout/PipLayout/Pip.js.map +1 -0
- package/dist/esm/src/core/components/CallLayout/PipLayout/index.js +8 -0
- package/dist/esm/src/core/components/CallLayout/PipLayout/index.js.map +1 -0
- package/dist/esm/src/core/components/CallLayout/SpeakerLayout.js +103 -0
- package/dist/esm/src/core/components/CallLayout/SpeakerLayout.js.map +1 -0
- package/dist/esm/src/core/components/CallLayout/hooks.js +62 -0
- package/dist/esm/src/core/components/CallLayout/hooks.js.map +1 -0
- package/dist/esm/src/core/components/ParticipantView/DefaultParticipantViewUI.js +94 -0
- package/dist/esm/src/core/components/ParticipantView/DefaultParticipantViewUI.js.map +1 -0
- package/dist/esm/src/core/components/ParticipantView/ParticipantActionsContextMenu.js +97 -0
- package/dist/esm/src/core/components/ParticipantView/ParticipantActionsContextMenu.js.map +1 -0
- package/dist/esm/src/core/components/ParticipantView/ParticipantView.js +65 -0
- package/dist/esm/src/core/components/ParticipantView/ParticipantView.js.map +1 -0
- package/dist/esm/src/core/components/ParticipantView/ParticipantViewContext.js +7 -0
- package/dist/esm/src/core/components/ParticipantView/ParticipantViewContext.js.map +1 -0
- package/dist/esm/src/core/components/StreamCall/StreamCall.js +8 -0
- package/dist/esm/src/core/components/StreamCall/StreamCall.js.map +1 -0
- package/dist/esm/src/core/components/StreamVideo/StreamVideo.js +11 -0
- package/dist/esm/src/core/components/StreamVideo/StreamVideo.js.map +1 -0
- package/dist/esm/src/core/components/Video/BaseVideo.js +41 -0
- package/dist/esm/src/core/components/Video/BaseVideo.js.map +1 -0
- package/dist/esm/src/core/components/Video/BaseVideoPlaceholder.js +21 -0
- package/dist/esm/src/core/components/Video/BaseVideoPlaceholder.js.map +1 -0
- package/dist/esm/src/core/components/Video/DefaultPictureInPicturePlaceholder.js +12 -0
- package/dist/esm/src/core/components/Video/DefaultPictureInPicturePlaceholder.js.map +1 -0
- package/dist/esm/src/core/components/Video/DefaultVideoPlaceholder.js +12 -0
- package/dist/esm/src/core/components/Video/DefaultVideoPlaceholder.js.map +1 -0
- package/dist/esm/src/core/components/Video/Video.js +88 -0
- package/dist/esm/src/core/components/Video/Video.js.map +1 -0
- package/dist/esm/src/core/hooks/useCalculateHardLimit.js +59 -0
- package/dist/esm/src/core/hooks/useCalculateHardLimit.js.map +1 -0
- package/dist/esm/src/core/hooks/usePictureInPictureState.js +24 -0
- package/dist/esm/src/core/hooks/usePictureInPictureState.js.map +1 -0
- package/dist/esm/src/core/hooks/useTrackElementVisibility.js +14 -0
- package/dist/esm/src/core/hooks/useTrackElementVisibility.js.map +1 -0
- package/dist/esm/src/embedded/EmbeddedClientProvider.js +83 -0
- package/dist/esm/src/embedded/EmbeddedClientProvider.js.map +1 -0
- package/dist/esm/src/embedded/call/CallControls.js +65 -0
- package/dist/esm/src/embedded/call/CallControls.js.map +1 -0
- package/dist/esm/src/embedded/call/CallHeader.js +57 -0
- package/dist/esm/src/embedded/call/CallHeader.js.map +1 -0
- package/dist/esm/src/embedded/call/CallLayout.js +63 -0
- package/dist/esm/src/embedded/call/CallLayout.js.map +1 -0
- package/dist/esm/src/embedded/call/CallStateRouter.js +87 -0
- package/dist/esm/src/embedded/call/CallStateRouter.js.map +1 -0
- package/dist/esm/src/embedded/call/EmbeddedCall.js +12 -0
- package/dist/esm/src/embedded/call/EmbeddedCall.js.map +1 -0
- package/dist/esm/src/embedded/context/ConfigurationContext.js +21 -0
- package/dist/esm/src/embedded/context/ConfigurationContext.js.map +1 -0
- package/dist/esm/src/embedded/hooks/useCallDuration.js +32 -0
- package/dist/esm/src/embedded/hooks/useCallDuration.js.map +1 -0
- package/dist/esm/src/embedded/hooks/useEmbeddedClient.js +40 -0
- package/dist/esm/src/embedded/hooks/useEmbeddedClient.js.map +1 -0
- package/dist/esm/src/embedded/hooks/useInitializeCall.js +39 -0
- package/dist/esm/src/embedded/hooks/useInitializeCall.js.map +1 -0
- package/dist/esm/src/embedded/hooks/useInitializeVideoClient.js +93 -0
- package/dist/esm/src/embedded/hooks/useInitializeVideoClient.js.map +1 -0
- package/dist/esm/src/embedded/hooks/useIsLivestreamPaused.js +42 -0
- package/dist/esm/src/embedded/hooks/useIsLivestreamPaused.js.map +1 -0
- package/dist/esm/src/embedded/hooks/useLayout.js +122 -0
- package/dist/esm/src/embedded/hooks/useLayout.js.map +1 -0
- package/dist/esm/src/embedded/hooks/useNoiseCancellationLoader.js +48 -0
- package/dist/esm/src/embedded/hooks/useNoiseCancellationLoader.js.map +1 -0
- package/dist/esm/src/embedded/hooks/useWakeLock.js +34 -0
- package/dist/esm/src/embedded/hooks/useWakeLock.js.map +1 -0
- package/dist/esm/src/embedded/livestream/EmbeddedLivestream.js +11 -0
- package/dist/esm/src/embedded/livestream/EmbeddedLivestream.js.map +1 -0
- package/dist/esm/src/embedded/livestream/LivestreamUI.js +17 -0
- package/dist/esm/src/embedded/livestream/LivestreamUI.js.map +1 -0
- package/dist/esm/src/embedded/livestream/host/HostLayout.js +76 -0
- package/dist/esm/src/embedded/livestream/host/HostLayout.js.map +1 -0
- package/dist/esm/src/embedded/livestream/host/HostStateRouter.js +110 -0
- package/dist/esm/src/embedded/livestream/host/HostStateRouter.js.map +1 -0
- package/dist/esm/src/embedded/livestream/viewer/ViewerLayout.js +74 -0
- package/dist/esm/src/embedded/livestream/viewer/ViewerLayout.js.map +1 -0
- package/dist/esm/src/embedded/livestream/viewer/ViewerLobby.js +109 -0
- package/dist/esm/src/embedded/livestream/viewer/ViewerLobby.js.map +1 -0
- package/dist/esm/src/embedded/livestream/viewer/ViewerStateRouter.js +105 -0
- package/dist/esm/src/embedded/livestream/viewer/ViewerStateRouter.js.map +1 -0
- package/dist/esm/src/embedded/shared/BlurToggleButton/BlurToggleButton.js +65 -0
- package/dist/esm/src/embedded/shared/BlurToggleButton/BlurToggleButton.js.map +1 -0
- package/dist/esm/src/embedded/shared/CallFeedback/CallEndedScreen.js +34 -0
- package/dist/esm/src/embedded/shared/CallFeedback/CallEndedScreen.js.map +1 -0
- package/dist/esm/src/embedded/shared/CallFeedback/CallFeedback.js +35 -0
- package/dist/esm/src/embedded/shared/CallFeedback/CallFeedback.js.map +1 -0
- package/dist/esm/src/embedded/shared/CallFeedback/RatingScreen.js +18 -0
- package/dist/esm/src/embedded/shared/CallFeedback/RatingScreen.js.map +1 -0
- package/dist/esm/src/embedded/shared/CallFeedback/StarRating.js +37 -0
- package/dist/esm/src/embedded/shared/CallFeedback/StarRating.js.map +1 -0
- package/dist/esm/src/embedded/shared/CallFeedback/ThankYouScreen.js +34 -0
- package/dist/esm/src/embedded/shared/CallFeedback/ThankYouScreen.js.map +1 -0
- package/dist/esm/src/embedded/shared/ConnectionNotification/ConnectionNotification.js +56 -0
- package/dist/esm/src/embedded/shared/ConnectionNotification/ConnectionNotification.js.map +1 -0
- package/dist/esm/src/embedded/shared/EmbeddedParticipantViewUI/EmbeddedParticipantViewUI.js +42 -0
- package/dist/esm/src/embedded/shared/EmbeddedParticipantViewUI/EmbeddedParticipantViewUI.js.map +1 -0
- package/dist/esm/src/embedded/shared/JoinError/JoinError.js +34 -0
- package/dist/esm/src/embedded/shared/JoinError/JoinError.js.map +1 -0
- package/dist/esm/src/embedded/shared/Lobby/DeviceControls.js +44 -0
- package/dist/esm/src/embedded/shared/Lobby/DeviceControls.js.map +1 -0
- package/dist/esm/src/embedded/shared/Lobby/DisabledDeviceButton.js +31 -0
- package/dist/esm/src/embedded/shared/Lobby/DisabledDeviceButton.js.map +1 -0
- package/dist/esm/src/embedded/shared/Lobby/Lobby.js +45 -0
- package/dist/esm/src/embedded/shared/Lobby/Lobby.js.map +1 -0
- package/dist/esm/src/embedded/shared/Lobby/ToggleCameraButton.js +40 -0
- package/dist/esm/src/embedded/shared/Lobby/ToggleCameraButton.js.map +1 -0
- package/dist/esm/src/embedded/shared/Lobby/ToggleMicButton.js +41 -0
- package/dist/esm/src/embedded/shared/Lobby/ToggleMicButton.js.map +1 -0
- package/dist/esm/src/embedded/shared/Lobby/VideoPreviewFallbacks.js +50 -0
- package/dist/esm/src/embedded/shared/Lobby/VideoPreviewFallbacks.js.map +1 -0
- package/dist/esm/src/embedded/shared/ViewersCount/ViewersCount.js +31 -0
- package/dist/esm/src/embedded/shared/ViewersCount/ViewersCount.js.map +1 -0
- package/dist/esm/src/hooks/useDeviceList.js +40 -0
- package/dist/esm/src/hooks/useDeviceList.js.map +1 -0
- package/dist/esm/src/hooks/useDragToScroll.js +116 -0
- package/dist/esm/src/hooks/useDragToScroll.js.map +1 -0
- package/dist/esm/src/hooks/useFloatingUIPreset.js +34 -0
- package/dist/esm/src/hooks/useFloatingUIPreset.js.map +1 -0
- package/dist/esm/src/hooks/useLoopbackRecording.js +138 -0
- package/dist/esm/src/hooks/useLoopbackRecording.js.map +1 -0
- package/dist/esm/src/hooks/useModeration.js +135 -0
- package/dist/esm/src/hooks/useModeration.js.map +1 -0
- package/dist/esm/src/hooks/usePersistedDevicePreferences.js +16 -0
- package/dist/esm/src/hooks/usePersistedDevicePreferences.js.map +1 -0
- package/dist/esm/src/hooks/useRequestPermission.js +41 -0
- package/dist/esm/src/hooks/useRequestPermission.js.map +1 -0
- package/dist/esm/src/hooks/useScrollPosition.js +66 -0
- package/dist/esm/src/hooks/useScrollPosition.js.map +1 -0
- package/dist/esm/src/translations/en.json.js +177 -0
- package/dist/esm/src/translations/en.json.js.map +1 -0
- package/dist/esm/src/translations/index.js +6 -0
- package/dist/esm/src/translations/index.js.map +1 -0
- package/dist/esm/src/utilities/applyElementToRef.js +10 -0
- package/dist/esm/src/utilities/applyElementToRef.js.map +1 -0
- package/dist/esm/src/utilities/callControlHandler.js +29 -0
- package/dist/esm/src/utilities/callControlHandler.js.map +1 -0
- package/dist/esm/src/utilities/chunk.js +7 -0
- package/dist/esm/src/utilities/chunk.js.map +1 -0
- package/dist/esm/src/utilities/filter.js +94 -0
- package/dist/esm/src/utilities/filter.js.map +1 -0
- package/dist/esm/src/utilities/isComponentType.js +10 -0
- package/dist/esm/src/utilities/isComponentType.js.map +1 -0
- package/dist/esm/src/utilities/normalizeString.js +11 -0
- package/dist/esm/src/utilities/normalizeString.js.map +1 -0
- package/dist/esm/src/wrappers/LivestreamPlayer/LivestreamPlayer.js +105 -0
- package/dist/esm/src/wrappers/LivestreamPlayer/LivestreamPlayer.js.map +1 -0
- package/dist/index.cjs.js +138 -5
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/src/hooks/index.d.ts +1 -0
- package/dist/src/hooks/useLoopbackRecording.d.ts +23 -0
- package/dist/src/hooks/useRequestPermission.d.ts +2 -2
- package/index.ts +4 -0
- package/package.json +14 -10
- package/src/components/CallControls/ScreenShareButton.tsx +5 -2
- package/src/components/CallControls/ToggleAudioButton.tsx +6 -2
- package/src/components/CallControls/ToggleVideoButton.tsx +6 -2
- package/src/core/components/ParticipantView/ParticipantActionsContextMenu.tsx +16 -12
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useLoopbackRecording.ts +207 -0
- package/src/hooks/useRequestPermission.ts +4 -2
- package/dist/background-filters-D2U5UBbH.es.js.map +0 -1
- package/dist/embedded-BackgroundFilters-D2U5UBbH.es.js +0 -420
- package/dist/embedded-BackgroundFilters-D2U5UBbH.es.js.map +0 -1
- package/dist/embedded-CallStatsLatencyChart-Bj5OSYzg.es.js +0 -57
- package/dist/embedded-CallStatsLatencyChart-Bj5OSYzg.es.js.map +0 -1
- package/dist/embedded.es.js +0 -3536
- package/dist/embedded.es.js.map +0 -1
- package/dist/index.es.js +0 -3291
- package/dist/index.es.js.map +0 -1
- package/dist/latency-chart-Bj5OSYzg.es.js.map +0 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useI18n, useCall } from '@stream-io/video-react-bindings';
|
|
3
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
4
|
+
import clsx from 'clsx';
|
|
5
|
+
import { hasScreenShare } from '@stream-io/video-client';
|
|
6
|
+
import '../../../../components/BackgroundFilters/BackgroundFiltersProvider.js';
|
|
7
|
+
import '../../../../components/Button/CompositeButton.js';
|
|
8
|
+
import { IconButton } from '../../../../components/Button/IconButton.js';
|
|
9
|
+
import '@floating-ui/react';
|
|
10
|
+
import '../../../../components/CallControls/RecordCallButton.js';
|
|
11
|
+
import '../../../../components/CallControls/ReactionsButton.js';
|
|
12
|
+
import { Icon } from '../../../../components/Icon/Icon.js';
|
|
13
|
+
import '../../../../components/DeviceSettings/DeviceSettings.js';
|
|
14
|
+
import '../../../../components/DropdownSelect/DropdownSelect.js';
|
|
15
|
+
import '../../../../components/Menu/MenuToggle.js';
|
|
16
|
+
import '../../../../components/CallControls/CancelCallButton.js';
|
|
17
|
+
import '../../../../components/CallControls/CallStatsButton.js';
|
|
18
|
+
import '../../../../components/CallParticipantsList/CallParticipantsList.js';
|
|
19
|
+
import '../../../../components/CallParticipantsList/CallParticipantListingItem.js';
|
|
20
|
+
import '../../../../components/CallStats/CallStats.js';
|
|
21
|
+
import '../../../../components/NoiseCancellation/NoiseCancellationProvider.js';
|
|
22
|
+
import '../../../../components/RingingCall/RingingCall.js';
|
|
23
|
+
import '../../../../components/Permissions/PermissionRequests.js';
|
|
24
|
+
import '../../Video/Video.js';
|
|
25
|
+
import '../../Video/BaseVideo.js';
|
|
26
|
+
import '../../Video/DefaultVideoPlaceholder.js';
|
|
27
|
+
import '../../ParticipantView/ParticipantViewContext.js';
|
|
28
|
+
import { ParticipantView } from '../../ParticipantView/ParticipantView.js';
|
|
29
|
+
import { DefaultParticipantViewUI } from '../../ParticipantView/DefaultParticipantViewUI.js';
|
|
30
|
+
import { useFilteredParticipants, usePaginatedLayoutSortPreset } from '../hooks.js';
|
|
31
|
+
import { chunk } from '../../../../utilities/chunk.js';
|
|
32
|
+
|
|
33
|
+
const getGridDensity = (count) => {
|
|
34
|
+
if (count === 1)
|
|
35
|
+
return 'single';
|
|
36
|
+
if (count <= 5)
|
|
37
|
+
return 'small';
|
|
38
|
+
if (count <= 9)
|
|
39
|
+
return 'medium';
|
|
40
|
+
if (count <= 16)
|
|
41
|
+
return 'large';
|
|
42
|
+
return 'overflow';
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* A grid-based PIP layout with pagination support.
|
|
46
|
+
* Use this when you need a more structured grid view in PIP mode.
|
|
47
|
+
*/
|
|
48
|
+
const Grid = (props) => {
|
|
49
|
+
const { t } = useI18n();
|
|
50
|
+
const { excludeLocalParticipant = false, filterParticipants, mirrorLocalParticipantVideo = true, groupSize = 9, pageArrowsVisible = true, VideoPlaceholder, ParticipantViewUI = DefaultParticipantViewUI, } = props;
|
|
51
|
+
const [page, setPage] = useState(0);
|
|
52
|
+
const [wrapperElement, setWrapperElement] = useState(null);
|
|
53
|
+
const call = useCall();
|
|
54
|
+
const participants = useFilteredParticipants({
|
|
55
|
+
excludeLocalParticipant,
|
|
56
|
+
filterParticipants,
|
|
57
|
+
});
|
|
58
|
+
const screenSharingParticipant = participants.find((p) => hasScreenShare(p));
|
|
59
|
+
usePaginatedLayoutSortPreset(call);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (!wrapperElement || !call)
|
|
62
|
+
return;
|
|
63
|
+
return call.setViewport(wrapperElement);
|
|
64
|
+
}, [wrapperElement, call]);
|
|
65
|
+
const participantGroups = useMemo(() => chunk(participants, groupSize), [participants, groupSize]);
|
|
66
|
+
const pageCount = participantGroups.length;
|
|
67
|
+
if (page > pageCount - 1) {
|
|
68
|
+
setPage(Math.max(0, pageCount - 1));
|
|
69
|
+
}
|
|
70
|
+
const selectedGroup = participantGroups[page];
|
|
71
|
+
const mirror = mirrorLocalParticipantVideo ? undefined : false;
|
|
72
|
+
if (!call)
|
|
73
|
+
return null;
|
|
74
|
+
return (jsxs("div", { className: "str-video__pip-layout str-video__pip-layout--grid", ref: setWrapperElement, children: [screenSharingParticipant &&
|
|
75
|
+
(screenSharingParticipant.isLocalParticipant ? (jsxs("div", { className: "str-video__pip-screen-share-local", children: [jsx(Icon, { icon: "screen-share-off" }), jsx("span", { className: "str-video__pip-screen-share-local__title", children: t('You are presenting your screen') })] })) : (jsx(ParticipantView, { participant: screenSharingParticipant, trackType: "screenShareTrack", muteAudio: true, mirror: false, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }))), jsxs("div", { className: "str-video__pip-layout__grid-container", children: [pageArrowsVisible && page > 0 && (jsx(IconButton, { icon: "caret-left", onClick: () => setPage((currentPage) => Math.max(0, currentPage - 1)), className: "str-video__pip-layout__pagination-button str-video__pip-layout__pagination-button--left" })), selectedGroup && (jsx("div", { className: clsx('str-video__pip-layout__grid', `str-video__pip-layout__grid--${getGridDensity(selectedGroup.length)}`), children: selectedGroup.map((participant) => (jsx(ParticipantView, { participant: participant, muteAudio: true, mirror: mirror, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }, participant.sessionId))) })), pageArrowsVisible && page < pageCount - 1 && (jsx(IconButton, { icon: "caret-right", onClick: () => setPage((currentPage) => Math.min(pageCount - 1, currentPage + 1)), className: "str-video__pip-layout__pagination-button str-video__pip-layout__pagination-button--right" }))] })] }));
|
|
76
|
+
};
|
|
77
|
+
Grid.displayName = 'PipLayout.Grid';
|
|
78
|
+
|
|
79
|
+
export { Grid };
|
|
80
|
+
//# sourceMappingURL=Grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Grid.js","sources":["../../../../../../../../../src/core/components/CallLayout/PipLayout/Grid.tsx"],"sourcesContent":["import { useCall, useI18n } from '@stream-io/video-react-bindings';\nimport { useEffect, useMemo, useState } from 'react';\nimport clsx from 'clsx';\nimport { hasScreenShare } from '@stream-io/video-client';\nimport { Icon, IconButton } from '../../../../components';\nimport {\n DefaultParticipantViewUI,\n ParticipantView,\n} from '../../ParticipantView';\nimport {\n useFilteredParticipants,\n usePaginatedLayoutSortPreset,\n} from '../hooks';\nimport { chunk } from '../../../../utilities';\nimport { PipLayoutProps } from './Pip';\n\ntype GridDensity = 'single' | 'small' | 'medium' | 'large' | 'overflow';\n\nexport type PipLayoutGridProps = PipLayoutProps & {\n /**\n * The number of participants to display per page.\n * @default 9\n */\n groupSize?: number;\n\n /**\n * Whether to show pagination arrows when there are multiple pages.\n * @default true\n */\n pageArrowsVisible?: boolean;\n};\n\nconst getGridDensity = (count: number): GridDensity => {\n if (count === 1) return 'single';\n if (count <= 5) return 'small';\n if (count <= 9) return 'medium';\n if (count <= 16) return 'large';\n return 'overflow';\n};\n\n/**\n * A grid-based PIP layout with pagination support.\n * Use this when you need a more structured grid view in PIP mode.\n */\nexport const Grid = (props: PipLayoutGridProps) => {\n const { t } = useI18n();\n const {\n excludeLocalParticipant = false,\n filterParticipants,\n mirrorLocalParticipantVideo = true,\n groupSize = 9,\n pageArrowsVisible = true,\n VideoPlaceholder,\n ParticipantViewUI = DefaultParticipantViewUI,\n } = props;\n\n const [page, setPage] = useState(0);\n const [wrapperElement, setWrapperElement] = useState<HTMLDivElement | null>(\n null,\n );\n\n const call = useCall();\n const participants = useFilteredParticipants({\n excludeLocalParticipant,\n filterParticipants,\n });\n const screenSharingParticipant = participants.find((p) => hasScreenShare(p));\n\n usePaginatedLayoutSortPreset(call);\n\n useEffect(() => {\n if (!wrapperElement || !call) return;\n return call.setViewport(wrapperElement);\n }, [wrapperElement, call]);\n\n const participantGroups = useMemo(\n () => chunk(participants, groupSize),\n [participants, groupSize],\n );\n\n const pageCount = participantGroups.length;\n\n if (page > pageCount - 1) {\n setPage(Math.max(0, pageCount - 1));\n }\n\n const selectedGroup = participantGroups[page];\n const mirror = mirrorLocalParticipantVideo ? undefined : false;\n\n if (!call) return null;\n\n return (\n <div\n className=\"str-video__pip-layout str-video__pip-layout--grid\"\n ref={setWrapperElement}\n >\n {screenSharingParticipant &&\n (screenSharingParticipant.isLocalParticipant ? (\n <div className=\"str-video__pip-screen-share-local\">\n <Icon icon=\"screen-share-off\" />\n <span className=\"str-video__pip-screen-share-local__title\">\n {t('You are presenting your screen')}\n </span>\n </div>\n ) : (\n <ParticipantView\n participant={screenSharingParticipant}\n trackType=\"screenShareTrack\"\n muteAudio\n mirror={false}\n VideoPlaceholder={VideoPlaceholder}\n ParticipantViewUI={ParticipantViewUI}\n />\n ))}\n <div className=\"str-video__pip-layout__grid-container\">\n {pageArrowsVisible && page > 0 && (\n <IconButton\n icon=\"caret-left\"\n onClick={() =>\n setPage((currentPage) => Math.max(0, currentPage - 1))\n }\n className=\"str-video__pip-layout__pagination-button str-video__pip-layout__pagination-button--left\"\n />\n )}\n {selectedGroup && (\n <div\n className={clsx(\n 'str-video__pip-layout__grid',\n `str-video__pip-layout__grid--${getGridDensity(selectedGroup.length)}`,\n )}\n >\n {selectedGroup.map((participant) => (\n <ParticipantView\n key={participant.sessionId}\n participant={participant}\n muteAudio\n mirror={mirror}\n VideoPlaceholder={VideoPlaceholder}\n ParticipantViewUI={ParticipantViewUI}\n />\n ))}\n </div>\n )}\n {pageArrowsVisible && page < pageCount - 1 && (\n <IconButton\n icon=\"caret-right\"\n onClick={() =>\n setPage((currentPage) => Math.min(pageCount - 1, currentPage + 1))\n }\n className=\"str-video__pip-layout__pagination-button str-video__pip-layout__pagination-button--right\"\n />\n )}\n </div>\n </div>\n );\n};\n\nGrid.displayName = 'PipLayout.Grid';\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import '../../Audio/Audio.js';
|
|
3
|
+
import { ParticipantsAudio } from '../../Audio/ParticipantsAudio.js';
|
|
4
|
+
import { useRawRemoteParticipants } from '../hooks.js';
|
|
5
|
+
|
|
6
|
+
const Host = () => {
|
|
7
|
+
const remoteParticipants = useRawRemoteParticipants();
|
|
8
|
+
return jsx(ParticipantsAudio, { participants: remoteParticipants });
|
|
9
|
+
};
|
|
10
|
+
Host.displayName = 'PipLayout.Host';
|
|
11
|
+
|
|
12
|
+
export { Host };
|
|
13
|
+
//# sourceMappingURL=Host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Host.js","sources":["../../../../../../../../../src/core/components/CallLayout/PipLayout/Host.tsx"],"sourcesContent":["import { ParticipantsAudio } from '../../Audio';\nimport { useRawRemoteParticipants } from '../hooks';\n\nexport const Host = () => {\n const remoteParticipants = useRawRemoteParticipants();\n return <ParticipantsAudio participants={remoteParticipants} />;\n};\n\nHost.displayName = 'PipLayout.Host';\n"],"names":["_jsx"],"mappings":";;;;;AAGO,MAAM,IAAI,GAAG,MAAK;AACvB,IAAA,MAAM,kBAAkB,GAAG,wBAAwB,EAAE;AACrD,IAAA,OAAOA,IAAC,iBAAiB,EAAA,EAAC,YAAY,EAAE,kBAAkB,GAAI;AAChE;AAEA,IAAI,CAAC,WAAW,GAAG,gBAAgB;;;;"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useI18n, useCall } from '@stream-io/video-react-bindings';
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { hasScreenShare } from '@stream-io/video-client';
|
|
5
|
+
import 'clsx';
|
|
6
|
+
import '../../../../components/BackgroundFilters/BackgroundFiltersProvider.js';
|
|
7
|
+
import '../../../../components/Button/CompositeButton.js';
|
|
8
|
+
import '../../../../components/Button/IconButton.js';
|
|
9
|
+
import '@floating-ui/react';
|
|
10
|
+
import '../../../../components/CallControls/RecordCallButton.js';
|
|
11
|
+
import '../../../../components/CallControls/ReactionsButton.js';
|
|
12
|
+
import { Icon } from '../../../../components/Icon/Icon.js';
|
|
13
|
+
import '../../../../components/DeviceSettings/DeviceSettings.js';
|
|
14
|
+
import '../../../../components/DropdownSelect/DropdownSelect.js';
|
|
15
|
+
import '../../../../components/Menu/MenuToggle.js';
|
|
16
|
+
import '../../../../components/CallControls/CancelCallButton.js';
|
|
17
|
+
import '../../../../components/CallControls/CallStatsButton.js';
|
|
18
|
+
import '../../../../components/CallParticipantsList/CallParticipantsList.js';
|
|
19
|
+
import '../../../../components/CallParticipantsList/CallParticipantListingItem.js';
|
|
20
|
+
import '../../../../components/CallStats/CallStats.js';
|
|
21
|
+
import '../../../../components/NoiseCancellation/NoiseCancellationProvider.js';
|
|
22
|
+
import '../../../../components/RingingCall/RingingCall.js';
|
|
23
|
+
import '../../../../components/Permissions/PermissionRequests.js';
|
|
24
|
+
import '../../Video/Video.js';
|
|
25
|
+
import '../../Video/BaseVideo.js';
|
|
26
|
+
import '../../Video/DefaultVideoPlaceholder.js';
|
|
27
|
+
import '../../ParticipantView/ParticipantViewContext.js';
|
|
28
|
+
import { ParticipantView } from '../../ParticipantView/ParticipantView.js';
|
|
29
|
+
import { DefaultParticipantViewUI } from '../../ParticipantView/DefaultParticipantViewUI.js';
|
|
30
|
+
import { useFilteredParticipants, usePaginatedLayoutSortPreset } from '../hooks.js';
|
|
31
|
+
|
|
32
|
+
const Pip = (props) => {
|
|
33
|
+
const { t } = useI18n();
|
|
34
|
+
const { excludeLocalParticipant = false, filterParticipants, mirrorLocalParticipantVideo = true, VideoPlaceholder, ParticipantViewUI = DefaultParticipantViewUI, } = props;
|
|
35
|
+
const [layoutWrapperElement, setLayoutWrapperElement] = useState(null);
|
|
36
|
+
const call = useCall();
|
|
37
|
+
const participants = useFilteredParticipants({
|
|
38
|
+
excludeLocalParticipant,
|
|
39
|
+
filterParticipants,
|
|
40
|
+
});
|
|
41
|
+
const screenSharingParticipant = participants.find((p) => hasScreenShare(p));
|
|
42
|
+
usePaginatedLayoutSortPreset(call);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (!layoutWrapperElement || !call)
|
|
45
|
+
return;
|
|
46
|
+
return call.setViewport(layoutWrapperElement);
|
|
47
|
+
}, [layoutWrapperElement, call]);
|
|
48
|
+
const mirror = mirrorLocalParticipantVideo ? undefined : false;
|
|
49
|
+
if (!call)
|
|
50
|
+
return null;
|
|
51
|
+
return (jsxs("div", { className: "str-video__pip-layout", ref: setLayoutWrapperElement, children: [screenSharingParticipant &&
|
|
52
|
+
(screenSharingParticipant.isLocalParticipant ? (jsxs("div", { className: "str-video__pip-screen-share-local", children: [jsx(Icon, { icon: "screen-share-off" }), jsx("span", { className: "str-video__pip-screen-share-local__title", children: t('You are presenting your screen') })] })) : (jsx(ParticipantView, { participant: screenSharingParticipant, trackType: "screenShareTrack", muteAudio: true, mirror: false, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }))), participants.map((participant) => (jsx(ParticipantView, { participant: participant, muteAudio: true, mirror: mirror, VideoPlaceholder: VideoPlaceholder, ParticipantViewUI: ParticipantViewUI }, participant.sessionId)))] }));
|
|
53
|
+
};
|
|
54
|
+
Pip.displayName = 'PipLayout.Pip';
|
|
55
|
+
|
|
56
|
+
export { Pip };
|
|
57
|
+
//# sourceMappingURL=Pip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pip.js","sources":["../../../../../../../../../src/core/components/CallLayout/PipLayout/Pip.tsx"],"sourcesContent":["import { useCall, useI18n } from '@stream-io/video-react-bindings';\nimport { useEffect, useState } from 'react';\n\nimport { hasScreenShare } from '@stream-io/video-client';\nimport { Icon } from '../../../../components';\nimport {\n DefaultParticipantViewUI,\n ParticipantView,\n ParticipantViewProps,\n} from '../../ParticipantView';\nimport {\n ParticipantFilter,\n ParticipantPredicate,\n useFilteredParticipants,\n usePaginatedLayoutSortPreset,\n} from '../hooks';\n\nexport type PipLayoutProps = {\n /**\n * Whether to exclude the local participant from the grid.\n * @default false\n */\n excludeLocalParticipant?: boolean;\n\n /**\n * Predicate to filter call participants or a filter object.\n * @example\n * // With a predicate:\n * <PipLayout\n * filterParticipants={p => p.roles.includes('student')}\n * />\n * @example\n * // With a filter object:\n * <PipLayout\n * filterParticipants={{\n * $or: [\n * { roles: { $contains: 'student' } },\n * { isPinned: true },\n * ],\n * }}\n * />\n */\n filterParticipants?: ParticipantPredicate | ParticipantFilter;\n\n /**\n * When set to `false` disables mirroring of the local partipant's video.\n * @default true\n */\n mirrorLocalParticipantVideo?: boolean;\n} & Pick<ParticipantViewProps, 'ParticipantViewUI' | 'VideoPlaceholder'>;\n\nexport const Pip = (props: PipLayoutProps) => {\n const { t } = useI18n();\n const {\n excludeLocalParticipant = false,\n filterParticipants,\n mirrorLocalParticipantVideo = true,\n VideoPlaceholder,\n ParticipantViewUI = DefaultParticipantViewUI,\n } = props;\n const [layoutWrapperElement, setLayoutWrapperElement] =\n useState<HTMLDivElement | null>(null);\n\n const call = useCall();\n const participants = useFilteredParticipants({\n excludeLocalParticipant,\n filterParticipants,\n });\n const screenSharingParticipant = participants.find((p) => hasScreenShare(p));\n\n usePaginatedLayoutSortPreset(call);\n\n useEffect(() => {\n if (!layoutWrapperElement || !call) return;\n return call.setViewport(layoutWrapperElement);\n }, [layoutWrapperElement, call]);\n\n const mirror = mirrorLocalParticipantVideo ? undefined : false;\n\n if (!call) return null;\n\n return (\n <div className=\"str-video__pip-layout\" ref={setLayoutWrapperElement}>\n {screenSharingParticipant &&\n (screenSharingParticipant.isLocalParticipant ? (\n <div className=\"str-video__pip-screen-share-local\">\n <Icon icon=\"screen-share-off\" />\n <span className=\"str-video__pip-screen-share-local__title\">\n {t('You are presenting your screen')}\n </span>\n </div>\n ) : (\n <ParticipantView\n participant={screenSharingParticipant}\n trackType=\"screenShareTrack\"\n muteAudio\n mirror={false}\n VideoPlaceholder={VideoPlaceholder}\n ParticipantViewUI={ParticipantViewUI}\n />\n ))}\n {participants.map((participant) => (\n <ParticipantView\n key={participant.sessionId}\n participant={participant}\n muteAudio\n mirror={mirror}\n VideoPlaceholder={VideoPlaceholder}\n ParticipantViewUI={ParticipantViewUI}\n />\n ))}\n </div>\n );\n};\n\nPip.displayName = 'PipLayout.Pip';\n"],"names":["_jsxs","_jsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDO,MAAM,GAAG,GAAG,CAAC,KAAqB,KAAI;AAC3C,IAAA,MAAM,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE;AACvB,IAAA,MAAM,EACJ,uBAAuB,GAAG,KAAK,EAC/B,kBAAkB,EAClB,2BAA2B,GAAG,IAAI,EAClC,gBAAgB,EAChB,iBAAiB,GAAG,wBAAwB,GAC7C,GAAG,KAAK;IACT,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,GACnD,QAAQ,CAAwB,IAAI,CAAC;AAEvC,IAAA,MAAM,IAAI,GAAG,OAAO,EAAE;IACtB,MAAM,YAAY,GAAG,uBAAuB,CAAC;QAC3C,uBAAuB;QACvB,kBAAkB;AACnB,KAAA,CAAC;AACF,IAAA,MAAM,wBAAwB,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,CAAC;IAE5E,4BAA4B,CAAC,IAAI,CAAC;IAElC,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,oBAAoB,IAAI,CAAC,IAAI;YAAE;AACpC,QAAA,OAAO,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC;AAC/C,IAAA,CAAC,EAAE,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC;IAEhC,MAAM,MAAM,GAAG,2BAA2B,GAAG,SAAS,GAAG,KAAK;AAE9D,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,IAAI;IAEtB,QACEA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,uBAAuB,EAAC,GAAG,EAAE,uBAAuB,EAAA,QAAA,EAAA,CAChE,wBAAwB;iBACtB,wBAAwB,CAAC,kBAAkB,IAC1CA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mCAAmC,aAChDC,GAAA,CAAC,IAAI,IAAC,IAAI,EAAC,kBAAkB,EAAA,CAAG,EAChCA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,0CAA0C,YACvD,CAAC,CAAC,gCAAgC,CAAC,EAAA,CAC/B,IACH,KAENA,GAAA,CAAC,eAAe,EAAA,EACd,WAAW,EAAE,wBAAwB,EACrC,SAAS,EAAC,kBAAkB,EAC5B,SAAS,EAAA,IAAA,EACT,MAAM,EAAE,KAAK,EACb,gBAAgB,EAAE,gBAAgB,EAClC,iBAAiB,EAAE,iBAAiB,EAAA,CACpC,CACH,CAAC,EACH,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,MAC5BA,GAAA,CAAC,eAAe,EAAA,EAEd,WAAW,EAAE,WAAW,EACxB,SAAS,EAAA,IAAA,EACT,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,gBAAgB,EAClC,iBAAiB,EAAE,iBAAiB,EAAA,EAL/B,WAAW,CAAC,SAAS,CAM1B,CACH,CAAC,CAAA,EAAA,CACE;AAEV;AAEA,GAAG,CAAC,WAAW,GAAG,eAAe;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../../../../../src/core/components/CallLayout/PipLayout/index.ts"],"sourcesContent":["import { Pip } from './Pip';\nimport { Host } from './Host';\nimport { Grid } from './Grid';\n\nexport const PipLayout = { Pip, Host, Grid };\n"],"names":[],"mappings":";;;;AAIO,MAAM,SAAS,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI;;;;"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { hasScreenShare } from '@stream-io/video-client';
|
|
5
|
+
import { useCall, useCallStateHooks, useSpeakerLayoutSortPreset } from '@stream-io/video-react-bindings';
|
|
6
|
+
import '../ParticipantView/ParticipantViewContext.js';
|
|
7
|
+
import '../../../components/Menu/MenuToggle.js';
|
|
8
|
+
import { ParticipantView } from '../ParticipantView/ParticipantView.js';
|
|
9
|
+
import { DefaultParticipantViewUI } from '../ParticipantView/DefaultParticipantViewUI.js';
|
|
10
|
+
import '../../../components/BackgroundFilters/BackgroundFiltersProvider.js';
|
|
11
|
+
import '../../../components/Button/CompositeButton.js';
|
|
12
|
+
import { IconButton } from '../../../components/Button/IconButton.js';
|
|
13
|
+
import '@floating-ui/react';
|
|
14
|
+
import { useVerticalScrollPosition, useHorizontalScrollPosition } from '../../../hooks/useScrollPosition.js';
|
|
15
|
+
import { useDragToScroll } from '../../../hooks/useDragToScroll.js';
|
|
16
|
+
import '../../../components/CallControls/RecordCallButton.js';
|
|
17
|
+
import '../../../components/CallControls/ReactionsButton.js';
|
|
18
|
+
import '../../../components/DeviceSettings/DeviceSettings.js';
|
|
19
|
+
import '../../../components/DropdownSelect/DropdownSelect.js';
|
|
20
|
+
import '../../../components/CallControls/CancelCallButton.js';
|
|
21
|
+
import '../../../components/CallControls/CallStatsButton.js';
|
|
22
|
+
import '../../../components/CallParticipantsList/CallParticipantsList.js';
|
|
23
|
+
import '../../../components/CallParticipantsList/CallParticipantListingItem.js';
|
|
24
|
+
import '../../../components/CallStats/CallStats.js';
|
|
25
|
+
import '../../../components/NoiseCancellation/NoiseCancellationProvider.js';
|
|
26
|
+
import '../../../components/RingingCall/RingingCall.js';
|
|
27
|
+
import '../../../components/Permissions/PermissionRequests.js';
|
|
28
|
+
import '../Video/Video.js';
|
|
29
|
+
import '../Video/BaseVideo.js';
|
|
30
|
+
import '../Video/DefaultVideoPlaceholder.js';
|
|
31
|
+
import { useRawRemoteParticipants, useFilteredParticipants } from './hooks.js';
|
|
32
|
+
import { useCalculateHardLimit } from '../../hooks/useCalculateHardLimit.js';
|
|
33
|
+
import '../Audio/Audio.js';
|
|
34
|
+
import { ParticipantsAudio } from '../Audio/ParticipantsAudio.js';
|
|
35
|
+
|
|
36
|
+
const DefaultParticipantViewUIBar = () => (jsx(DefaultParticipantViewUI, { menuPlacement: "top-end" }));
|
|
37
|
+
const SpeakerLayout = ({ ParticipantViewUIBar = DefaultParticipantViewUIBar, ParticipantViewUISpotlight = DefaultParticipantViewUI, VideoPlaceholder, PictureInPicturePlaceholder, participantsBarPosition = 'bottom', participantsBarLimit, mirrorLocalParticipantVideo = true, excludeLocalParticipant = false, filterParticipants, pageArrowsVisible = true, muted, enableDragToScroll = false, }) => {
|
|
38
|
+
const call = useCall();
|
|
39
|
+
const { useParticipants } = useCallStateHooks();
|
|
40
|
+
const allParticipants = useParticipants();
|
|
41
|
+
const remoteParticipants = useRawRemoteParticipants();
|
|
42
|
+
const [participantInSpotlight, ...otherParticipants] = useFilteredParticipants({ excludeLocalParticipant, filterParticipants });
|
|
43
|
+
const [participantsBarWrapperElement, setParticipantsBarWrapperElement] = useState(null);
|
|
44
|
+
const [participantsBarElement, setParticipantsBarElement] = useState(null);
|
|
45
|
+
const [buttonsWrapperElement, setButtonsWrapperElement] = useState(null);
|
|
46
|
+
const isSpeakerScreenSharing = participantInSpotlight && hasScreenShare(participantInSpotlight);
|
|
47
|
+
const hardLimit = useCalculateHardLimit(buttonsWrapperElement, participantsBarElement, participantsBarLimit);
|
|
48
|
+
const isVertical = participantsBarPosition === 'left' || participantsBarPosition === 'right';
|
|
49
|
+
const isHorizontal = participantsBarPosition === 'top' || participantsBarPosition === 'bottom';
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!participantsBarWrapperElement || !call)
|
|
52
|
+
return;
|
|
53
|
+
const cleanup = call.setViewport(participantsBarWrapperElement);
|
|
54
|
+
return () => cleanup?.();
|
|
55
|
+
}, [participantsBarWrapperElement, call]);
|
|
56
|
+
const isOneOnOneCall = allParticipants.length === 2;
|
|
57
|
+
useSpeakerLayoutSortPreset(call, isOneOnOneCall);
|
|
58
|
+
useDragToScroll(participantsBarWrapperElement, {
|
|
59
|
+
enabled: enableDragToScroll,
|
|
60
|
+
});
|
|
61
|
+
let participantsWithAppliedLimit = otherParticipants;
|
|
62
|
+
const hardLimitToApply = isVertical
|
|
63
|
+
? hardLimit.vertical
|
|
64
|
+
: hardLimit.horizontal;
|
|
65
|
+
if (typeof participantsBarLimit !== 'undefined' &&
|
|
66
|
+
hardLimitToApply !== null) {
|
|
67
|
+
participantsWithAppliedLimit = otherParticipants.slice(0,
|
|
68
|
+
// subtract 1 if speaker is sharing screen as
|
|
69
|
+
// that one is rendered independently from otherParticipants array
|
|
70
|
+
hardLimitToApply - (isSpeakerScreenSharing ? 1 : 0));
|
|
71
|
+
}
|
|
72
|
+
const mirror = mirrorLocalParticipantVideo ? undefined : false;
|
|
73
|
+
if (!call)
|
|
74
|
+
return null;
|
|
75
|
+
const renderParticipantsBar = participantsBarPosition &&
|
|
76
|
+
(participantsWithAppliedLimit.length > 0 || isSpeakerScreenSharing);
|
|
77
|
+
return (jsxs("div", { className: "str-video__speaker-layout__wrapper", children: [!muted && jsx(ParticipantsAudio, { participants: remoteParticipants }), jsxs("div", { className: clsx('str-video__speaker-layout', participantsBarPosition &&
|
|
78
|
+
`str-video__speaker-layout--variant-${participantsBarPosition}`), children: [jsx("div", { className: "str-video__speaker-layout__spotlight", children: participantInSpotlight && (jsx(ParticipantView, { participant: participantInSpotlight, muteAudio: true, mirror: mirror, trackType: isSpeakerScreenSharing ? 'screenShareTrack' : 'videoTrack', ParticipantViewUI: ParticipantViewUISpotlight, VideoPlaceholder: VideoPlaceholder, PictureInPicturePlaceholder: PictureInPicturePlaceholder })) }), renderParticipantsBar && (jsxs("div", { ref: setButtonsWrapperElement, className: "str-video__speaker-layout__participants-bar-buttons-wrapper", children: [jsx("div", { className: "str-video__speaker-layout__participants-bar-wrapper", ref: setParticipantsBarWrapperElement, children: jsxs("div", { ref: setParticipantsBarElement, className: "str-video__speaker-layout__participants-bar", children: [isSpeakerScreenSharing && (jsx("div", { className: "str-video__speaker-layout__participant-tile", children: jsx(ParticipantView, { participant: participantInSpotlight, ParticipantViewUI: ParticipantViewUIBar, VideoPlaceholder: VideoPlaceholder, PictureInPicturePlaceholder: PictureInPicturePlaceholder, mirror: mirror, muteAudio: true }) }, participantInSpotlight.sessionId)), participantsWithAppliedLimit.map((participant) => (jsx("div", { className: "str-video__speaker-layout__participant-tile", children: jsx(ParticipantView, { participant: participant, ParticipantViewUI: ParticipantViewUIBar, VideoPlaceholder: VideoPlaceholder, PictureInPicturePlaceholder: PictureInPicturePlaceholder, mirror: mirror, muteAudio: true }) }, participant.sessionId)))] }) }), pageArrowsVisible && isVertical && (jsx(VerticalScrollButtons, { scrollWrapper: participantsBarWrapperElement })), pageArrowsVisible && isHorizontal && (jsx(HorizontalScrollButtons, { scrollWrapper: participantsBarWrapperElement }))] }))] })] }));
|
|
79
|
+
};
|
|
80
|
+
SpeakerLayout.displayName = 'SpeakerLayout';
|
|
81
|
+
const HorizontalScrollButtons = ({ scrollWrapper, }) => {
|
|
82
|
+
const scrollPosition = useHorizontalScrollPosition(scrollWrapper);
|
|
83
|
+
const scrollStartClickHandler = () => {
|
|
84
|
+
scrollWrapper?.scrollBy({ left: -150, behavior: 'smooth' });
|
|
85
|
+
};
|
|
86
|
+
const scrollEndClickHandler = () => {
|
|
87
|
+
scrollWrapper?.scrollBy({ left: 150, behavior: 'smooth' });
|
|
88
|
+
};
|
|
89
|
+
return (jsxs(Fragment, { children: [scrollPosition && scrollPosition !== 'start' && (jsx(IconButton, { onClick: scrollStartClickHandler, icon: "caret-left", className: "str-video__speaker-layout__participants-bar--button-left" })), scrollPosition && scrollPosition !== 'end' && (jsx(IconButton, { onClick: scrollEndClickHandler, icon: "caret-right", className: "str-video__speaker-layout__participants-bar--button-right" }))] }));
|
|
90
|
+
};
|
|
91
|
+
const VerticalScrollButtons = ({ scrollWrapper, }) => {
|
|
92
|
+
const scrollPosition = useVerticalScrollPosition(scrollWrapper);
|
|
93
|
+
const scrollTopClickHandler = () => {
|
|
94
|
+
scrollWrapper?.scrollBy({ top: -150, behavior: 'smooth' });
|
|
95
|
+
};
|
|
96
|
+
const scrollBottomClickHandler = () => {
|
|
97
|
+
scrollWrapper?.scrollBy({ top: 150, behavior: 'smooth' });
|
|
98
|
+
};
|
|
99
|
+
return (jsxs(Fragment, { children: [scrollPosition && scrollPosition !== 'top' && (jsx(IconButton, { onClick: scrollTopClickHandler, icon: "caret-up", className: "str-video__speaker-layout__participants-bar--button-top" })), scrollPosition && scrollPosition !== 'bottom' && (jsx(IconButton, { onClick: scrollBottomClickHandler, icon: "caret-down", className: "str-video__speaker-layout__participants-bar--button-bottom" }))] }));
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export { SpeakerLayout };
|
|
103
|
+
//# sourceMappingURL=SpeakerLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpeakerLayout.js","sources":["../../../../../../../../src/core/components/CallLayout/SpeakerLayout.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport clsx from 'clsx';\nimport { hasScreenShare } from '@stream-io/video-client';\nimport {\n useCall,\n useCallStateHooks,\n useSpeakerLayoutSortPreset,\n} from '@stream-io/video-react-bindings';\n\nimport {\n DefaultParticipantViewUI,\n ParticipantView,\n ParticipantViewProps,\n} from '../ParticipantView';\nimport { IconButton } from '../../../components';\nimport {\n useDragToScroll,\n useHorizontalScrollPosition,\n useVerticalScrollPosition,\n} from '../../../hooks';\nimport {\n ParticipantFilter,\n ParticipantPredicate,\n useFilteredParticipants,\n useRawRemoteParticipants,\n} from './hooks';\nimport { useCalculateHardLimit } from '../../hooks/useCalculateHardLimit';\nimport { ParticipantsAudio } from '../Audio';\n\nexport type SpeakerLayoutProps = {\n /**\n * The UI to be used for the participant in the spotlight.\n */\n ParticipantViewUISpotlight?: ParticipantViewProps['ParticipantViewUI'];\n\n /**\n * The UI to be used for the participants in the participants bar.\n */\n ParticipantViewUIBar?: ParticipantViewProps['ParticipantViewUI'];\n\n /**\n * The position of the participants who are not in focus.\n * Providing `null` will hide the bar.\n */\n participantsBarPosition?: 'top' | 'bottom' | 'left' | 'right' | null;\n\n /**\n * Hard limits the number of the participants rendered in the participants bar.\n * Providing string `dynamic` will calculate hard limit based on screen width/height.\n */\n participantsBarLimit?: 'dynamic' | number;\n\n /**\n * When set to `true` will exclude the local participant from layout.\n * @default false\n */\n excludeLocalParticipant?: boolean;\n\n /**\n * Predicate to filter call participants or a filter object.\n * @example\n * // With a predicate:\n * <SpeakerLayout\n * filterParticipants={p => p.roles.includes('student')}\n * />\n * @example\n * // With a filter object:\n * <SpeakerLayout\n * filterParticipants={{\n * $or: [\n * { roles: { $contains: 'student' } },\n * { isPinned: true },\n * ],\n * }}\n * />\n */\n filterParticipants?: ParticipantPredicate | ParticipantFilter;\n\n /**\n * When set to `false` disables mirroring of the local participant's video.\n * @default true\n */\n mirrorLocalParticipantVideo?: boolean;\n\n /**\n * Turns on/off the pagination arrows.\n * @default true\n */\n pageArrowsVisible?: boolean;\n\n /**\n * Whether the layout is muted. Defaults to `false`.\n */\n muted?: boolean;\n\n /**\n * Whether to enable drag-to-scroll functionality on the participants bar.\n * @default false\n */\n enableDragToScroll?: boolean;\n} & Pick<\n ParticipantViewProps,\n 'VideoPlaceholder' | 'PictureInPicturePlaceholder'\n>;\n\nconst DefaultParticipantViewUIBar = () => (\n <DefaultParticipantViewUI menuPlacement=\"top-end\" />\n);\n\nexport const SpeakerLayout = ({\n ParticipantViewUIBar = DefaultParticipantViewUIBar,\n ParticipantViewUISpotlight = DefaultParticipantViewUI,\n VideoPlaceholder,\n PictureInPicturePlaceholder,\n participantsBarPosition = 'bottom',\n participantsBarLimit,\n mirrorLocalParticipantVideo = true,\n excludeLocalParticipant = false,\n filterParticipants,\n pageArrowsVisible = true,\n muted,\n enableDragToScroll = false,\n}: SpeakerLayoutProps) => {\n const call = useCall();\n const { useParticipants } = useCallStateHooks();\n const allParticipants = useParticipants();\n const remoteParticipants = useRawRemoteParticipants();\n const [participantInSpotlight, ...otherParticipants] =\n useFilteredParticipants({ excludeLocalParticipant, filterParticipants });\n const [participantsBarWrapperElement, setParticipantsBarWrapperElement] =\n useState<HTMLDivElement | null>(null);\n const [participantsBarElement, setParticipantsBarElement] =\n useState<HTMLDivElement | null>(null);\n const [buttonsWrapperElement, setButtonsWrapperElement] =\n useState<HTMLDivElement | null>(null);\n\n const isSpeakerScreenSharing =\n participantInSpotlight && hasScreenShare(participantInSpotlight);\n const hardLimit = useCalculateHardLimit(\n buttonsWrapperElement,\n participantsBarElement,\n participantsBarLimit,\n );\n\n const isVertical =\n participantsBarPosition === 'left' || participantsBarPosition === 'right';\n const isHorizontal =\n participantsBarPosition === 'top' || participantsBarPosition === 'bottom';\n\n useEffect(() => {\n if (!participantsBarWrapperElement || !call) return;\n\n const cleanup = call.setViewport(participantsBarWrapperElement);\n\n return () => cleanup?.();\n }, [participantsBarWrapperElement, call]);\n\n const isOneOnOneCall = allParticipants.length === 2;\n useSpeakerLayoutSortPreset(call, isOneOnOneCall);\n useDragToScroll(participantsBarWrapperElement, {\n enabled: enableDragToScroll,\n });\n\n let participantsWithAppliedLimit = otherParticipants;\n\n const hardLimitToApply = isVertical\n ? hardLimit.vertical\n : hardLimit.horizontal;\n\n if (\n typeof participantsBarLimit !== 'undefined' &&\n hardLimitToApply !== null\n ) {\n participantsWithAppliedLimit = otherParticipants.slice(\n 0,\n // subtract 1 if speaker is sharing screen as\n // that one is rendered independently from otherParticipants array\n hardLimitToApply - (isSpeakerScreenSharing ? 1 : 0),\n );\n }\n\n const mirror = mirrorLocalParticipantVideo ? undefined : false;\n\n if (!call) return null;\n\n const renderParticipantsBar =\n participantsBarPosition &&\n (participantsWithAppliedLimit.length > 0 || isSpeakerScreenSharing);\n return (\n <div className=\"str-video__speaker-layout__wrapper\">\n {!muted && <ParticipantsAudio participants={remoteParticipants} />}\n <div\n className={clsx(\n 'str-video__speaker-layout',\n participantsBarPosition &&\n `str-video__speaker-layout--variant-${participantsBarPosition}`,\n )}\n >\n <div className=\"str-video__speaker-layout__spotlight\">\n {participantInSpotlight && (\n <ParticipantView\n participant={participantInSpotlight}\n muteAudio={true}\n mirror={mirror}\n trackType={\n isSpeakerScreenSharing ? 'screenShareTrack' : 'videoTrack'\n }\n ParticipantViewUI={ParticipantViewUISpotlight}\n VideoPlaceholder={VideoPlaceholder}\n PictureInPicturePlaceholder={PictureInPicturePlaceholder}\n />\n )}\n </div>\n {renderParticipantsBar && (\n <div\n ref={setButtonsWrapperElement}\n className=\"str-video__speaker-layout__participants-bar-buttons-wrapper\"\n >\n <div\n className=\"str-video__speaker-layout__participants-bar-wrapper\"\n ref={setParticipantsBarWrapperElement}\n >\n <div\n ref={setParticipantsBarElement}\n className=\"str-video__speaker-layout__participants-bar\"\n >\n {isSpeakerScreenSharing && (\n <div\n className=\"str-video__speaker-layout__participant-tile\"\n key={participantInSpotlight.sessionId}\n >\n <ParticipantView\n participant={participantInSpotlight}\n ParticipantViewUI={ParticipantViewUIBar}\n VideoPlaceholder={VideoPlaceholder}\n PictureInPicturePlaceholder={PictureInPicturePlaceholder}\n mirror={mirror}\n muteAudio={true}\n />\n </div>\n )}\n {participantsWithAppliedLimit.map((participant) => (\n <div\n className=\"str-video__speaker-layout__participant-tile\"\n key={participant.sessionId}\n >\n <ParticipantView\n participant={participant}\n ParticipantViewUI={ParticipantViewUIBar}\n VideoPlaceholder={VideoPlaceholder}\n PictureInPicturePlaceholder={PictureInPicturePlaceholder}\n mirror={mirror}\n muteAudio={true}\n />\n </div>\n ))}\n </div>\n </div>\n {pageArrowsVisible && isVertical && (\n <VerticalScrollButtons\n scrollWrapper={participantsBarWrapperElement}\n />\n )}\n {pageArrowsVisible && isHorizontal && (\n <HorizontalScrollButtons\n scrollWrapper={participantsBarWrapperElement}\n />\n )}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nSpeakerLayout.displayName = 'SpeakerLayout';\n\ntype ScrollButtonsProps<T extends HTMLElement> = {\n scrollWrapper: T | null;\n};\n\nconst HorizontalScrollButtons = <T extends HTMLElement>({\n scrollWrapper,\n}: ScrollButtonsProps<T>) => {\n const scrollPosition = useHorizontalScrollPosition(scrollWrapper);\n\n const scrollStartClickHandler = () => {\n scrollWrapper?.scrollBy({ left: -150, behavior: 'smooth' });\n };\n\n const scrollEndClickHandler = () => {\n scrollWrapper?.scrollBy({ left: 150, behavior: 'smooth' });\n };\n return (\n <>\n {scrollPosition && scrollPosition !== 'start' && (\n <IconButton\n onClick={scrollStartClickHandler}\n icon=\"caret-left\"\n className=\"str-video__speaker-layout__participants-bar--button-left\"\n />\n )}\n {scrollPosition && scrollPosition !== 'end' && (\n <IconButton\n onClick={scrollEndClickHandler}\n icon=\"caret-right\"\n className=\"str-video__speaker-layout__participants-bar--button-right\"\n />\n )}\n </>\n );\n};\n\nconst VerticalScrollButtons = <T extends HTMLElement>({\n scrollWrapper,\n}: ScrollButtonsProps<T>) => {\n const scrollPosition = useVerticalScrollPosition(scrollWrapper);\n\n const scrollTopClickHandler = () => {\n scrollWrapper?.scrollBy({ top: -150, behavior: 'smooth' });\n };\n\n const scrollBottomClickHandler = () => {\n scrollWrapper?.scrollBy({ top: 150, behavior: 'smooth' });\n };\n return (\n <>\n {scrollPosition && scrollPosition !== 'top' && (\n <IconButton\n onClick={scrollTopClickHandler}\n icon=\"caret-up\"\n className=\"str-video__speaker-layout__participants-bar--button-top\"\n />\n )}\n {scrollPosition && scrollPosition !== 'bottom' && (\n <IconButton\n onClick={scrollBottomClickHandler}\n icon=\"caret-down\"\n className=\"str-video__speaker-layout__participants-bar--button-bottom\"\n />\n )}\n </>\n );\n};\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useMemo, useEffect } from 'react';
|
|
2
|
+
import { paginatedLayoutSortPreset, CallTypes, defaultSortPreset, hasScreenShare, hasAudio, hasVideo, isPinned } from '@stream-io/video-client';
|
|
3
|
+
import { useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
4
|
+
import { applyFilter } from '../../../utilities/filter.js';
|
|
5
|
+
|
|
6
|
+
const useFilteredParticipants = ({ excludeLocalParticipant = false, filterParticipants, }) => {
|
|
7
|
+
const { useParticipants, useRemoteParticipants } = useCallStateHooks();
|
|
8
|
+
const allParticipants = useParticipants();
|
|
9
|
+
const remoteParticipants = useRemoteParticipants();
|
|
10
|
+
return useMemo(() => {
|
|
11
|
+
const unfilteredParticipants = excludeLocalParticipant
|
|
12
|
+
? remoteParticipants
|
|
13
|
+
: allParticipants;
|
|
14
|
+
return filterParticipants
|
|
15
|
+
? applyParticipantsFilter(unfilteredParticipants, filterParticipants)
|
|
16
|
+
: unfilteredParticipants;
|
|
17
|
+
}, [
|
|
18
|
+
allParticipants,
|
|
19
|
+
remoteParticipants,
|
|
20
|
+
excludeLocalParticipant,
|
|
21
|
+
filterParticipants,
|
|
22
|
+
]);
|
|
23
|
+
};
|
|
24
|
+
const applyParticipantsFilter = (participants, filter) => {
|
|
25
|
+
const filterCallback = typeof filter === 'function'
|
|
26
|
+
? filter
|
|
27
|
+
: (participant) => applyFilter({
|
|
28
|
+
userId: participant.userId,
|
|
29
|
+
isSpeaking: participant.isSpeaking,
|
|
30
|
+
isDominantSpeaker: participant.isDominantSpeaker,
|
|
31
|
+
name: participant.name,
|
|
32
|
+
roles: participant.roles,
|
|
33
|
+
isPinned: isPinned(participant),
|
|
34
|
+
hasVideo: hasVideo(participant),
|
|
35
|
+
hasAudio: hasAudio(participant),
|
|
36
|
+
hasScreenShare: hasScreenShare(participant),
|
|
37
|
+
}, filter);
|
|
38
|
+
return participants.filter(filterCallback);
|
|
39
|
+
};
|
|
40
|
+
const usePaginatedLayoutSortPreset = (call) => {
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (!call)
|
|
43
|
+
return;
|
|
44
|
+
call.setSortParticipantsBy(paginatedLayoutSortPreset);
|
|
45
|
+
return () => {
|
|
46
|
+
resetSortPreset(call);
|
|
47
|
+
};
|
|
48
|
+
}, [call]);
|
|
49
|
+
};
|
|
50
|
+
const useRawRemoteParticipants = () => {
|
|
51
|
+
const { useRawParticipants } = useCallStateHooks();
|
|
52
|
+
const rawParticipants = useRawParticipants();
|
|
53
|
+
return useMemo(() => rawParticipants.filter((p) => !p.isLocalParticipant), [rawParticipants]);
|
|
54
|
+
};
|
|
55
|
+
const resetSortPreset = (call) => {
|
|
56
|
+
// reset the sorting to the default for the call type
|
|
57
|
+
const callConfig = CallTypes.get(call.type);
|
|
58
|
+
call.setSortParticipantsBy(callConfig.options.sortParticipantsBy || defaultSortPreset);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export { applyParticipantsFilter, useFilteredParticipants, usePaginatedLayoutSortPreset, useRawRemoteParticipants };
|
|
62
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sources":["../../../../../../../../src/core/components/CallLayout/hooks.ts"],"sourcesContent":["import { useEffect, useMemo } from 'react';\nimport {\n Call,\n CallTypes,\n defaultSortPreset,\n hasAudio,\n hasScreenShare,\n hasVideo,\n isPinned,\n paginatedLayoutSortPreset,\n StreamVideoParticipant,\n} from '@stream-io/video-client';\nimport { useCallStateHooks } from '@stream-io/video-react-bindings';\nimport { applyFilter, Filter } from '../../../utilities/filter';\n\nexport type FilterableParticipant = Pick<\n StreamVideoParticipant,\n 'userId' | 'isSpeaking' | 'isDominantSpeaker' | 'name' | 'roles'\n> & {\n isPinned: boolean;\n hasVideo: boolean;\n hasAudio: boolean;\n hasScreenShare: boolean;\n};\n\nexport type ParticipantFilter = Filter<FilterableParticipant>;\nexport type ParticipantPredicate = (\n participant: StreamVideoParticipant,\n) => boolean;\n\nexport const useFilteredParticipants = ({\n excludeLocalParticipant = false,\n filterParticipants,\n}: {\n excludeLocalParticipant?: boolean;\n filterParticipants?: ParticipantFilter | ParticipantPredicate;\n}) => {\n const { useParticipants, useRemoteParticipants } = useCallStateHooks();\n const allParticipants = useParticipants();\n const remoteParticipants = useRemoteParticipants();\n return useMemo(() => {\n const unfilteredParticipants = excludeLocalParticipant\n ? remoteParticipants\n : allParticipants;\n\n return filterParticipants\n ? applyParticipantsFilter(unfilteredParticipants, filterParticipants)\n : unfilteredParticipants;\n }, [\n allParticipants,\n remoteParticipants,\n excludeLocalParticipant,\n filterParticipants,\n ]);\n};\n\nexport const applyParticipantsFilter = (\n participants: StreamVideoParticipant[],\n filter: ParticipantPredicate | ParticipantFilter,\n) => {\n const filterCallback =\n typeof filter === 'function'\n ? filter\n : (participant: StreamVideoParticipant) =>\n applyFilter(\n {\n userId: participant.userId,\n isSpeaking: participant.isSpeaking,\n isDominantSpeaker: participant.isDominantSpeaker,\n name: participant.name,\n roles: participant.roles,\n isPinned: isPinned(participant),\n hasVideo: hasVideo(participant),\n hasAudio: hasAudio(participant),\n hasScreenShare: hasScreenShare(participant),\n },\n filter,\n );\n\n return participants.filter(filterCallback);\n};\n\nexport const usePaginatedLayoutSortPreset = (call: Call | undefined) => {\n useEffect(() => {\n if (!call) return;\n call.setSortParticipantsBy(paginatedLayoutSortPreset);\n return () => {\n resetSortPreset(call);\n };\n }, [call]);\n};\n\nexport const useRawRemoteParticipants = () => {\n const { useRawParticipants } = useCallStateHooks();\n const rawParticipants = useRawParticipants();\n return useMemo(\n () => rawParticipants.filter((p) => !p.isLocalParticipant),\n [rawParticipants],\n );\n};\n\nconst resetSortPreset = (call: Call) => {\n // reset the sorting to the default for the call type\n const callConfig = CallTypes.get(call.type);\n call.setSortParticipantsBy(\n callConfig.options.sortParticipantsBy || defaultSortPreset,\n );\n};\n"],"names":[],"mappings":";;;;;AA8BO,MAAM,uBAAuB,GAAG,CAAC,EACtC,uBAAuB,GAAG,KAAK,EAC/B,kBAAkB,GAInB,KAAI;IACH,MAAM,EAAE,eAAe,EAAE,qBAAqB,EAAE,GAAG,iBAAiB,EAAE;AACtE,IAAA,MAAM,eAAe,GAAG,eAAe,EAAE;AACzC,IAAA,MAAM,kBAAkB,GAAG,qBAAqB,EAAE;IAClD,OAAO,OAAO,CAAC,MAAK;QAClB,MAAM,sBAAsB,GAAG;AAC7B,cAAE;cACA,eAAe;AAEnB,QAAA,OAAO;AACL,cAAE,uBAAuB,CAAC,sBAAsB,EAAE,kBAAkB;cAClE,sBAAsB;AAC5B,IAAA,CAAC,EAAE;QACD,eAAe;QACf,kBAAkB;QAClB,uBAAuB;QACvB,kBAAkB;AACnB,KAAA,CAAC;AACJ;MAEa,uBAAuB,GAAG,CACrC,YAAsC,EACtC,MAAgD,KAC9C;AACF,IAAA,MAAM,cAAc,GAClB,OAAO,MAAM,KAAK;AAChB,UAAE;AACF,UAAE,CAAC,WAAmC,KAClC,WAAW,CACT;YACE,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,UAAU,EAAE,WAAW,CAAC,UAAU;YAClC,iBAAiB,EAAE,WAAW,CAAC,iBAAiB;YAChD,IAAI,EAAE,WAAW,CAAC,IAAI;YACtB,KAAK,EAAE,WAAW,CAAC,KAAK;AACxB,YAAA,QAAQ,EAAE,QAAQ,CAAC,WAAW,CAAC;AAC/B,YAAA,QAAQ,EAAE,QAAQ,CAAC,WAAW,CAAC;AAC/B,YAAA,QAAQ,EAAE,QAAQ,CAAC,WAAW,CAAC;AAC/B,YAAA,cAAc,EAAE,cAAc,CAAC,WAAW,CAAC;SAC5C,EACD,MAAM,CACP;AAET,IAAA,OAAO,YAAY,CAAC,MAAM,CAAC,cAAc,CAAC;AAC5C;AAEO,MAAM,4BAA4B,GAAG,CAAC,IAAsB,KAAI;IACrE,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,IAAI;YAAE;AACX,QAAA,IAAI,CAAC,qBAAqB,CAAC,yBAAyB,CAAC;AACrD,QAAA,OAAO,MAAK;YACV,eAAe,CAAC,IAAI,CAAC;AACvB,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AACZ;AAEO,MAAM,wBAAwB,GAAG,MAAK;AAC3C,IAAA,MAAM,EAAE,kBAAkB,EAAE,GAAG,iBAAiB,EAAE;AAClD,IAAA,MAAM,eAAe,GAAG,kBAAkB,EAAE;IAC5C,OAAO,OAAO,CACZ,MAAM,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,EAC1D,CAAC,eAAe,CAAC,CAClB;AACH;AAEA,MAAM,eAAe,GAAG,CAAC,IAAU,KAAI;;IAErC,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;IAC3C,IAAI,CAAC,qBAAqB,CACxB,UAAU,CAAC,OAAO,CAAC,kBAAkB,IAAI,iBAAiB,CAC3D;AACH,CAAC;;;;"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { hasScreenShare, SfuModels, hasAudio, hasVideo, hasPausedTrack } from '@stream-io/video-client';
|
|
4
|
+
import { useCallStateHooks, useCall, useI18n, useIsAudioConnecting, useIsVideoConnecting } from '@stream-io/video-react-bindings';
|
|
5
|
+
import clsx from 'clsx';
|
|
6
|
+
import '../../../components/BackgroundFilters/BackgroundFiltersProvider.js';
|
|
7
|
+
import '../../../components/Button/CompositeButton.js';
|
|
8
|
+
import { IconButton } from '../../../components/Button/IconButton.js';
|
|
9
|
+
import { Notification } from '../../../components/Notification/Notification.js';
|
|
10
|
+
import '../../../components/CallControls/RecordCallButton.js';
|
|
11
|
+
import '../../../components/CallControls/ReactionsButton.js';
|
|
12
|
+
import '@floating-ui/react';
|
|
13
|
+
import { Icon } from '../../../components/Icon/Icon.js';
|
|
14
|
+
import '../../../components/DeviceSettings/DeviceSettings.js';
|
|
15
|
+
import '../../../components/DropdownSelect/DropdownSelect.js';
|
|
16
|
+
import { MenuToggle } from '../../../components/Menu/MenuToggle.js';
|
|
17
|
+
import '../../../components/CallControls/CancelCallButton.js';
|
|
18
|
+
import '../../../components/CallControls/CallStatsButton.js';
|
|
19
|
+
import '../../../components/CallParticipantsList/CallParticipantsList.js';
|
|
20
|
+
import '../../../components/CallParticipantsList/CallParticipantListingItem.js';
|
|
21
|
+
import { LoadingIndicator } from '../../../components/LoadingIndicator/LoadingIndicator.js';
|
|
22
|
+
import '../../../components/CallStats/CallStats.js';
|
|
23
|
+
import '../../../components/NoiseCancellation/NoiseCancellationProvider.js';
|
|
24
|
+
import { Reaction } from '../../../components/Reaction/Reaction.js';
|
|
25
|
+
import '../../../components/RingingCall/RingingCall.js';
|
|
26
|
+
import '../../../components/Permissions/PermissionRequests.js';
|
|
27
|
+
import '../Video/Video.js';
|
|
28
|
+
import '../Video/BaseVideo.js';
|
|
29
|
+
import '../Video/DefaultVideoPlaceholder.js';
|
|
30
|
+
import { ParticipantActionsContextMenu } from './ParticipantActionsContextMenu.js';
|
|
31
|
+
import { useParticipantViewContext } from './ParticipantViewContext.js';
|
|
32
|
+
|
|
33
|
+
const ToggleButton = forwardRef(function ToggleButtonRender(props, ref) {
|
|
34
|
+
return jsx(IconButton, { enabled: props.menuShown, icon: "ellipsis", ref: ref });
|
|
35
|
+
});
|
|
36
|
+
const DefaultScreenShareOverlay = () => {
|
|
37
|
+
const call = useCall();
|
|
38
|
+
const { t } = useI18n();
|
|
39
|
+
const stopScreenShare = () => {
|
|
40
|
+
call?.screenShare.disable().catch((err) => {
|
|
41
|
+
console.error('Failed to stop screen sharing:', err);
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
return (jsxs("div", { className: "str-video__screen-share-overlay", children: [jsx(Icon, { icon: "screen-share-off" }), jsx("span", { className: "str-video__screen-share-overlay__title", children: t('You are presenting your screen') }), jsxs("button", { onClick: stopScreenShare, type: "button", className: "str-video__screen-share-overlay__button", children: [jsx(Icon, { icon: "close" }), " ", t('Stop Screen Sharing')] })] }));
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Rendered over a remote participant's tile when the browser's autoplay policy
|
|
48
|
+
* has blocked their audio. Selecting it calls `call.resumeAudio()`, unblocking
|
|
49
|
+
* every blocked element at once.
|
|
50
|
+
*/
|
|
51
|
+
const DefaultAudioBlockedNotification = () => {
|
|
52
|
+
const call = useCall();
|
|
53
|
+
const { t } = useI18n();
|
|
54
|
+
return (jsx("button", { type: "button", className: "str-video__audio-blocked-notification", onClick: call?.resumeAudio, "aria-live": "polite", children: jsxs("span", { className: "str-video__audio-blocked-notification__message", children: [jsx(Icon, { icon: "speaker" }), jsxs("span", { className: "str-video__audio-blocked-notification__text", children: [jsx("span", { className: "str-video__audio-blocked-notification__title", children: t('Audio is blocked by your system') }), jsx("span", { className: "str-video__audio-blocked-notification__subtitle", children: t('Click or tap to play audio') })] })] }) }));
|
|
55
|
+
};
|
|
56
|
+
const DefaultParticipantViewUI = ({ indicatorsVisible = true, menuPlacement = 'bottom-start', showMenuButton = true, ParticipantActionsContextMenu: ParticipantActionsContextMenu$1 = ParticipantActionsContextMenu, AudioBlockedNotification = DefaultAudioBlockedNotification, }) => {
|
|
57
|
+
const { participant, trackType } = useParticipantViewContext();
|
|
58
|
+
const { useAutoplayBlockedSessionIds } = useCallStateHooks();
|
|
59
|
+
const blockedSessionIds = useAutoplayBlockedSessionIds();
|
|
60
|
+
const isScreenSharing = hasScreenShare(participant);
|
|
61
|
+
const shouldShowAudioBlockedNotification = !participant.isLocalParticipant &&
|
|
62
|
+
trackType !== 'screenShareTrack' &&
|
|
63
|
+
blockedSessionIds.includes(participant.sessionId);
|
|
64
|
+
if (participant.isLocalParticipant &&
|
|
65
|
+
isScreenSharing &&
|
|
66
|
+
trackType === 'screenShareTrack') {
|
|
67
|
+
return (jsxs(Fragment, { children: [jsx(DefaultScreenShareOverlay, {}), jsx(ParticipantDetails, { indicatorsVisible: indicatorsVisible })] }));
|
|
68
|
+
}
|
|
69
|
+
return (jsxs(Fragment, { children: [showMenuButton && (jsx(MenuToggle, { strategy: "fixed", placement: menuPlacement, ToggleButton: ToggleButton, children: jsx(ParticipantActionsContextMenu$1, {}) })), jsx(Reaction, { participant: participant }), jsx(ParticipantDetails, { indicatorsVisible: indicatorsVisible }), AudioBlockedNotification && shouldShowAudioBlockedNotification && (jsx(AudioBlockedNotification, {}))] }));
|
|
70
|
+
};
|
|
71
|
+
const ParticipantDetails = ({ indicatorsVisible = true, }) => {
|
|
72
|
+
const { participant, trackType } = useParticipantViewContext();
|
|
73
|
+
const { isLocalParticipant, connectionQuality, pin, sessionId, name, userId, } = participant;
|
|
74
|
+
const call = useCall();
|
|
75
|
+
const { t } = useI18n();
|
|
76
|
+
const connectionQualityAsString = !!connectionQuality &&
|
|
77
|
+
SfuModels.ConnectionQuality[connectionQuality].toLowerCase();
|
|
78
|
+
const hasAudioTrack = hasAudio(participant);
|
|
79
|
+
const hasVideoTrack = hasVideo(participant);
|
|
80
|
+
const canUnpin = !!pin && pin.isLocalPin;
|
|
81
|
+
const isTrackPaused = trackType !== 'none' ? hasPausedTrack(participant, trackType) : false;
|
|
82
|
+
const isAudioConnecting = useIsAudioConnecting(participant);
|
|
83
|
+
const isVideoConnecting = useIsVideoConnecting(participant);
|
|
84
|
+
return (jsxs(Fragment, { children: [jsx("div", { className: "str-video__participant-details", children: jsxs("div", { className: "str-video__participant-details__name", children: [name || userId, indicatorsVisible && isAudioConnecting && (jsx(LoadingIndicator, { className: "str-video__participant-details__name--audio-connecting", tooltip: t('Audio is connecting...') })), indicatorsVisible && !hasAudioTrack && (jsx("span", { className: "str-video__participant-details__name--audio-muted" })), indicatorsVisible && isVideoConnecting && (jsx(LoadingIndicator, { className: "str-video__participant-details__name--video-connecting", tooltip: t('Video is connecting...') })), indicatorsVisible && !hasVideoTrack && (jsx("span", { className: "str-video__participant-details__name--video-muted" })), indicatorsVisible && isTrackPaused && (jsx("span", { title: t('Video paused due to insufficient bandwidth'), className: "str-video__participant-details__name--track-paused" })), indicatorsVisible && pin && (jsx("span", { title: canUnpin ? t('Unpin') : t('Pinned'), onClick: canUnpin ? () => call?.unpin(sessionId) : undefined, className: "str-video__participant-details__name--pinned" })), indicatorsVisible && jsx(SpeechIndicator, {})] }) }), indicatorsVisible && (jsx(Notification, { isVisible: isLocalParticipant &&
|
|
85
|
+
connectionQuality === SfuModels.ConnectionQuality.POOR, message: t('Poor connection quality'), children: connectionQualityAsString && (jsx("span", { className: clsx('str-video__participant-details__connection-quality', `str-video__participant-details__connection-quality--${connectionQualityAsString}`), title: connectionQualityAsString })) }))] }));
|
|
86
|
+
};
|
|
87
|
+
const SpeechIndicator = () => {
|
|
88
|
+
const { participant } = useParticipantViewContext();
|
|
89
|
+
const { isSpeaking, isDominantSpeaker } = participant;
|
|
90
|
+
return (jsxs("span", { className: clsx('str-video__speech-indicator', isSpeaking && 'str-video__speech-indicator--speaking', isDominantSpeaker && 'str-video__speech-indicator--dominant'), children: [jsx("span", { className: "str-video__speech-indicator__bar" }), jsx("span", { className: "str-video__speech-indicator__bar" }), jsx("span", { className: "str-video__speech-indicator__bar" })] }));
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export { DefaultAudioBlockedNotification, DefaultParticipantViewUI, DefaultScreenShareOverlay, ParticipantDetails, SpeechIndicator };
|
|
94
|
+
//# sourceMappingURL=DefaultParticipantViewUI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultParticipantViewUI.js","sources":["../../../../../../../../src/core/components/ParticipantView/DefaultParticipantViewUI.tsx"],"sourcesContent":["import { ComponentType, forwardRef } from 'react';\nimport { Placement } from '@floating-ui/react';\nimport {\n hasAudio,\n hasPausedTrack,\n hasScreenShare,\n hasVideo,\n SfuModels,\n} from '@stream-io/video-client';\nimport {\n useCall,\n useCallStateHooks,\n useI18n,\n useIsAudioConnecting,\n useIsVideoConnecting,\n} from '@stream-io/video-react-bindings';\nimport clsx from 'clsx';\n\nimport {\n Icon,\n IconButton,\n LoadingIndicator,\n MenuToggle,\n Notification,\n ToggleMenuButtonProps,\n} from '../../../components';\nimport { ParticipantActionsContextMenu as DefaultParticipantActionsContextMenu } from './ParticipantActionsContextMenu';\nimport { Reaction } from '../../../components/Reaction';\nimport { useParticipantViewContext } from './ParticipantViewContext';\n\nexport type DefaultParticipantViewUIProps = {\n /**\n * Turns on/off the status indicator icons (mute, connection quality, etc...).\n */\n indicatorsVisible?: boolean;\n /**\n * Placement of the context menu component when opened\n */\n menuPlacement?: Placement;\n /**\n * Option to show/hide menu button component\n */\n showMenuButton?: boolean;\n /**\n * Custom component to render the context menu\n */\n ParticipantActionsContextMenu?: ComponentType;\n /**\n * Rendered over the tile when this participant's audio is blocked by the\n * browser's autoplay policy. Selecting it calls {@link Call.resumeAudio} to\n * unblock audio. Defaults to\n * {@link DefaultAudioBlockedNotification}; pass `null` to disable.\n */\n AudioBlockedNotification?: ComponentType | null;\n};\n\nconst ToggleButton = forwardRef<HTMLButtonElement, ToggleMenuButtonProps>(\n function ToggleButtonRender(props, ref) {\n return <IconButton enabled={props.menuShown} icon=\"ellipsis\" ref={ref} />;\n },\n);\n\nexport const DefaultScreenShareOverlay = () => {\n const call = useCall();\n const { t } = useI18n();\n\n const stopScreenShare = () => {\n call?.screenShare.disable().catch((err) => {\n console.error('Failed to stop screen sharing:', err);\n });\n };\n\n return (\n <div className=\"str-video__screen-share-overlay\">\n <Icon icon=\"screen-share-off\" />\n <span className=\"str-video__screen-share-overlay__title\">\n {t('You are presenting your screen')}\n </span>\n <button\n onClick={stopScreenShare}\n type=\"button\"\n className=\"str-video__screen-share-overlay__button\"\n >\n <Icon icon=\"close\" /> {t('Stop Screen Sharing')}\n </button>\n </div>\n );\n};\n\n/**\n * Rendered over a remote participant's tile when the browser's autoplay policy\n * has blocked their audio. Selecting it calls `call.resumeAudio()`, unblocking\n * every blocked element at once.\n */\nexport const DefaultAudioBlockedNotification = () => {\n const call = useCall();\n const { t } = useI18n();\n\n return (\n <button\n type=\"button\"\n className=\"str-video__audio-blocked-notification\"\n onClick={call?.resumeAudio}\n aria-live=\"polite\"\n >\n <span className=\"str-video__audio-blocked-notification__message\">\n <Icon icon=\"speaker\" />\n <span className=\"str-video__audio-blocked-notification__text\">\n <span className=\"str-video__audio-blocked-notification__title\">\n {t('Audio is blocked by your system')}\n </span>\n <span className=\"str-video__audio-blocked-notification__subtitle\">\n {t('Click or tap to play audio')}\n </span>\n </span>\n </span>\n </button>\n );\n};\n\nexport const DefaultParticipantViewUI = ({\n indicatorsVisible = true,\n menuPlacement = 'bottom-start',\n showMenuButton = true,\n ParticipantActionsContextMenu = DefaultParticipantActionsContextMenu,\n AudioBlockedNotification = DefaultAudioBlockedNotification,\n}: DefaultParticipantViewUIProps) => {\n const { participant, trackType } = useParticipantViewContext();\n const { useAutoplayBlockedSessionIds } = useCallStateHooks();\n const blockedSessionIds = useAutoplayBlockedSessionIds();\n const isScreenSharing = hasScreenShare(participant);\n const shouldShowAudioBlockedNotification =\n !participant.isLocalParticipant &&\n trackType !== 'screenShareTrack' &&\n blockedSessionIds.includes(participant.sessionId);\n\n if (\n participant.isLocalParticipant &&\n isScreenSharing &&\n trackType === 'screenShareTrack'\n ) {\n return (\n <>\n <DefaultScreenShareOverlay />\n <ParticipantDetails indicatorsVisible={indicatorsVisible} />\n </>\n );\n }\n\n return (\n <>\n {showMenuButton && (\n <MenuToggle\n strategy=\"fixed\"\n placement={menuPlacement}\n ToggleButton={ToggleButton}\n >\n <ParticipantActionsContextMenu />\n </MenuToggle>\n )}\n <Reaction participant={participant} />\n <ParticipantDetails indicatorsVisible={indicatorsVisible} />\n {AudioBlockedNotification && shouldShowAudioBlockedNotification && (\n <AudioBlockedNotification />\n )}\n </>\n );\n};\n\nexport const ParticipantDetails = ({\n indicatorsVisible = true,\n}: Pick<DefaultParticipantViewUIProps, 'indicatorsVisible'>) => {\n const { participant, trackType } = useParticipantViewContext();\n const {\n isLocalParticipant,\n connectionQuality,\n pin,\n sessionId,\n name,\n userId,\n } = participant;\n const call = useCall();\n\n const { t } = useI18n();\n const connectionQualityAsString =\n !!connectionQuality &&\n SfuModels.ConnectionQuality[connectionQuality].toLowerCase();\n\n const hasAudioTrack = hasAudio(participant);\n const hasVideoTrack = hasVideo(participant);\n const canUnpin = !!pin && pin.isLocalPin;\n const isTrackPaused =\n trackType !== 'none' ? hasPausedTrack(participant, trackType) : false;\n\n const isAudioConnecting = useIsAudioConnecting(participant);\n const isVideoConnecting = useIsVideoConnecting(participant);\n\n return (\n <>\n <div className=\"str-video__participant-details\">\n <div className=\"str-video__participant-details__name\">\n {name || userId}\n {indicatorsVisible && isAudioConnecting && (\n <LoadingIndicator\n className=\"str-video__participant-details__name--audio-connecting\"\n tooltip={t('Audio is connecting...')}\n />\n )}\n {indicatorsVisible && !hasAudioTrack && (\n <span className=\"str-video__participant-details__name--audio-muted\" />\n )}\n {indicatorsVisible && isVideoConnecting && (\n <LoadingIndicator\n className=\"str-video__participant-details__name--video-connecting\"\n tooltip={t('Video is connecting...')}\n />\n )}\n {indicatorsVisible && !hasVideoTrack && (\n <span className=\"str-video__participant-details__name--video-muted\" />\n )}\n {indicatorsVisible && isTrackPaused && (\n <span\n title={t('Video paused due to insufficient bandwidth')}\n className=\"str-video__participant-details__name--track-paused\"\n />\n )}\n {indicatorsVisible && pin && (\n <span\n title={canUnpin ? t('Unpin') : t('Pinned')}\n onClick={canUnpin ? () => call?.unpin(sessionId) : undefined}\n className=\"str-video__participant-details__name--pinned\"\n />\n )}\n {indicatorsVisible && <SpeechIndicator />}\n </div>\n </div>\n {indicatorsVisible && (\n <Notification\n isVisible={\n isLocalParticipant &&\n connectionQuality === SfuModels.ConnectionQuality.POOR\n }\n message={t('Poor connection quality')}\n >\n {connectionQualityAsString && (\n <span\n className={clsx(\n 'str-video__participant-details__connection-quality',\n `str-video__participant-details__connection-quality--${connectionQualityAsString}`,\n )}\n title={connectionQualityAsString}\n />\n )}\n </Notification>\n )}\n </>\n );\n};\n\nexport const SpeechIndicator = () => {\n const { participant } = useParticipantViewContext();\n const { isSpeaking, isDominantSpeaker } = participant;\n return (\n <span\n className={clsx(\n 'str-video__speech-indicator',\n isSpeaking && 'str-video__speech-indicator--speaking',\n isDominantSpeaker && 'str-video__speech-indicator--dominant',\n )}\n >\n <span className=\"str-video__speech-indicator__bar\" />\n <span className=\"str-video__speech-indicator__bar\" />\n <span className=\"str-video__speech-indicator__bar\" />\n </span>\n );\n};\n"],"names":["_jsx","_jsxs","ParticipantActionsContextMenu","DefaultParticipantActionsContextMenu","_Fragment"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,MAAM,YAAY,GAAG,UAAU,CAC7B,SAAS,kBAAkB,CAAC,KAAK,EAAE,GAAG,EAAA;AACpC,IAAA,OAAOA,IAAC,UAAU,EAAA,EAAC,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAC,UAAU,EAAC,GAAG,EAAE,GAAG,GAAI;AAC3E,CAAC,CACF;AAEM,MAAM,yBAAyB,GAAG,MAAK;AAC5C,IAAA,MAAM,IAAI,GAAG,OAAO,EAAE;AACtB,IAAA,MAAM,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE;IAEvB,MAAM,eAAe,GAAG,MAAK;QAC3B,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,KAAI;AACxC,YAAA,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,CAAC;AACtD,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC;IAED,QACEC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,iCAAiC,aAC9CD,GAAA,CAAC,IAAI,EAAA,EAAC,IAAI,EAAC,kBAAkB,GAAG,EAChCA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,wCAAwC,EAAA,QAAA,EACrD,CAAC,CAAC,gCAAgC,CAAC,EAAA,CAC/B,EACPC,IAAA,CAAA,QAAA,EAAA,EACE,OAAO,EAAE,eAAe,EACxB,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,yCAAyC,EAAA,QAAA,EAAA,CAEnDD,GAAA,CAAC,IAAI,IAAC,IAAI,EAAC,OAAO,EAAA,CAAG,EAAA,GAAA,EAAE,CAAC,CAAC,qBAAqB,CAAC,CAAA,EAAA,CACxC,CAAA,EAAA,CACL;AAEV;AAEA;;;;AAIG;AACI,MAAM,+BAA+B,GAAG,MAAK;AAClD,IAAA,MAAM,IAAI,GAAG,OAAO,EAAE;AACtB,IAAA,MAAM,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE;AAEvB,IAAA,QACEA,GAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,uCAAuC,EACjD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAA,WAAA,EAChB,QAAQ,EAAA,QAAA,EAElBC,IAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,gDAAgD,EAAA,QAAA,EAAA,CAC9DD,GAAA,CAAC,IAAI,EAAA,EAAC,IAAI,EAAC,SAAS,EAAA,CAAG,EACvBC,IAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,6CAA6C,EAAA,QAAA,EAAA,CAC3DD,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,8CAA8C,EAAA,QAAA,EAC3D,CAAC,CAAC,iCAAiC,CAAC,EAAA,CAChC,EACPA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,iDAAiD,EAAA,QAAA,EAC9D,CAAC,CAAC,4BAA4B,CAAC,EAAA,CAC3B,CAAA,EAAA,CACF,CAAA,EAAA,CACF,EAAA,CACA;AAEb;AAEO,MAAM,wBAAwB,GAAG,CAAC,EACvC,iBAAiB,GAAG,IAAI,EACxB,aAAa,GAAG,cAAc,EAC9B,cAAc,GAAG,IAAI,iCACrBE,+BAA6B,GAAGC,6BAAoC,EACpE,wBAAwB,GAAG,+BAA+B,GAC5B,KAAI;IAClC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,yBAAyB,EAAE;AAC9D,IAAA,MAAM,EAAE,4BAA4B,EAAE,GAAG,iBAAiB,EAAE;AAC5D,IAAA,MAAM,iBAAiB,GAAG,4BAA4B,EAAE;AACxD,IAAA,MAAM,eAAe,GAAG,cAAc,CAAC,WAAW,CAAC;AACnD,IAAA,MAAM,kCAAkC,GACtC,CAAC,WAAW,CAAC,kBAAkB;AAC/B,QAAA,SAAS,KAAK,kBAAkB;AAChC,QAAA,iBAAiB,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC;IAEnD,IACE,WAAW,CAAC,kBAAkB;QAC9B,eAAe;QACf,SAAS,KAAK,kBAAkB,EAChC;AACA,QAAA,QACEF,IAAA,CAAAG,QAAA,EAAA,EAAA,QAAA,EAAA,CACEJ,GAAA,CAAC,yBAAyB,KAAG,EAC7BA,GAAA,CAAC,kBAAkB,EAAA,EAAC,iBAAiB,EAAE,iBAAiB,EAAA,CAAI,CAAA,EAAA,CAC3D;IAEP;IAEA,QACEC,IAAA,CAAAG,QAAA,EAAA,EAAA,QAAA,EAAA,CACG,cAAc,KACbJ,IAAC,UAAU,EAAA,EACT,QAAQ,EAAC,OAAO,EAChB,SAAS,EAAE,aAAa,EACxB,YAAY,EAAE,YAAY,YAE1BA,GAAA,CAACE,+BAA6B,EAAA,EAAA,CAAG,EAAA,CACtB,CACd,EACDF,IAAC,QAAQ,EAAA,EAAC,WAAW,EAAE,WAAW,EAAA,CAAI,EACtCA,GAAA,CAAC,kBAAkB,EAAA,EAAC,iBAAiB,EAAE,iBAAiB,GAAI,EAC3D,wBAAwB,IAAI,kCAAkC,KAC7DA,GAAA,CAAC,wBAAwB,EAAA,EAAA,CAAG,CAC7B,CAAA,EAAA,CACA;AAEP;AAEO,MAAM,kBAAkB,GAAG,CAAC,EACjC,iBAAiB,GAAG,IAAI,GACiC,KAAI;IAC7D,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,yBAAyB,EAAE;AAC9D,IAAA,MAAM,EACJ,kBAAkB,EAClB,iBAAiB,EACjB,GAAG,EACH,SAAS,EACT,IAAI,EACJ,MAAM,GACP,GAAG,WAAW;AACf,IAAA,MAAM,IAAI,GAAG,OAAO,EAAE;AAEtB,IAAA,MAAM,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE;AACvB,IAAA,MAAM,yBAAyB,GAC7B,CAAC,CAAC,iBAAiB;QACnB,SAAS,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC,WAAW,EAAE;AAE9D,IAAA,MAAM,aAAa,GAAG,QAAQ,CAAC,WAAW,CAAC;AAC3C,IAAA,MAAM,aAAa,GAAG,QAAQ,CAAC,WAAW,CAAC;IAC3C,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU;AACxC,IAAA,MAAM,aAAa,GACjB,SAAS,KAAK,MAAM,GAAG,cAAc,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG,KAAK;AAEvE,IAAA,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,WAAW,CAAC;AAC3D,IAAA,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,WAAW,CAAC;AAE3D,IAAA,QACEC,IAAA,CAAAG,QAAA,EAAA,EAAA,QAAA,EAAA,CACEJ,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,gCAAgC,EAAA,QAAA,EAC7CC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,sCAAsC,EAAA,QAAA,EAAA,CAClD,IAAI,IAAI,MAAM,EACd,iBAAiB,IAAI,iBAAiB,KACrCD,IAAC,gBAAgB,EAAA,EACf,SAAS,EAAC,wDAAwD,EAClE,OAAO,EAAE,CAAC,CAAC,wBAAwB,CAAC,EAAA,CACpC,CACH,EACA,iBAAiB,IAAI,CAAC,aAAa,KAClCA,cAAM,SAAS,EAAC,mDAAmD,EAAA,CAAG,CACvE,EACA,iBAAiB,IAAI,iBAAiB,KACrCA,GAAA,CAAC,gBAAgB,EAAA,EACf,SAAS,EAAC,wDAAwD,EAClE,OAAO,EAAE,CAAC,CAAC,wBAAwB,CAAC,EAAA,CACpC,CACH,EACA,iBAAiB,IAAI,CAAC,aAAa,KAClCA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,mDAAmD,GAAG,CACvE,EACA,iBAAiB,IAAI,aAAa,KACjCA,GAAA,CAAA,MAAA,EAAA,EACE,KAAK,EAAE,CAAC,CAAC,4CAA4C,CAAC,EACtD,SAAS,EAAC,oDAAoD,EAAA,CAC9D,CACH,EACA,iBAAiB,IAAI,GAAG,KACvBA,GAAA,CAAA,MAAA,EAAA,EACE,KAAK,EAAE,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAC1C,OAAO,EAAE,QAAQ,GAAG,MAAM,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,SAAS,EAC5D,SAAS,EAAC,8CAA8C,EAAA,CACxD,CACH,EACA,iBAAiB,IAAIA,GAAA,CAAC,eAAe,KAAG,CAAA,EAAA,CACrC,EAAA,CACF,EACL,iBAAiB,KAChBA,GAAA,CAAC,YAAY,EAAA,EACX,SAAS,EACP,kBAAkB;AAClB,oBAAA,iBAAiB,KAAK,SAAS,CAAC,iBAAiB,CAAC,IAAI,EAExD,OAAO,EAAE,CAAC,CAAC,yBAAyB,CAAC,YAEpC,yBAAyB,KACxBA,GAAA,CAAA,MAAA,EAAA,EACE,SAAS,EAAE,IAAI,CACb,oDAAoD,EACpD,CAAA,oDAAA,EAAuD,yBAAyB,EAAE,CACnF,EACD,KAAK,EAAE,yBAAyB,EAAA,CAChC,CACH,GACY,CAChB,CAAA,EAAA,CACA;AAEP;AAEO,MAAM,eAAe,GAAG,MAAK;AAClC,IAAA,MAAM,EAAE,WAAW,EAAE,GAAG,yBAAyB,EAAE;AACnD,IAAA,MAAM,EAAE,UAAU,EAAE,iBAAiB,EAAE,GAAG,WAAW;AACrD,IAAA,QACEC,IAAA,CAAA,MAAA,EAAA,EACE,SAAS,EAAE,IAAI,CACb,6BAA6B,EAC7B,UAAU,IAAI,uCAAuC,EACrD,iBAAiB,IAAI,uCAAuC,CAC7D,EAAA,QAAA,EAAA,CAEDD,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,kCAAkC,EAAA,CAAG,EACrDA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,kCAAkC,EAAA,CAAG,EACrDA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,kCAAkC,EAAA,CAAG,CAAA,EAAA,CAChD;AAEX;;;;"}
|