@stream-io/video-react-sdk 1.41.0 → 2.0.0-beta.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 +22 -6
- package/dist/{embedded-BackgroundFilters-folwWrgs.cjs.js → background-filters-DMStbSEg.cjs.js} +97 -71
- package/dist/background-filters-DMStbSEg.cjs.js.map +1 -0
- package/dist/{background-filters-folwWrgs.cjs.js → embedded-BackgroundFilters-DMStbSEg.cjs.js} +97 -71
- package/dist/embedded-BackgroundFilters-DMStbSEg.cjs.js.map +1 -0
- package/dist/embedded.cjs.js +2 -2
- 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} +97 -71
- 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 +136 -3
- 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/index.ts +4 -0
- package/package.json +15 -11
- package/src/components/BackgroundFilters/BackgroundFilters.tsx +139 -103
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useLoopbackRecording.ts +207 -0
- package/dist/background-filters-D2U5UBbH.es.js.map +0 -1
- package/dist/background-filters-folwWrgs.cjs.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-BackgroundFilters-folwWrgs.cjs.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,116 @@
|
|
|
1
|
+
import { useRef, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Enables drag-to-scroll functionality with momentum scrolling on a scrollable element.
|
|
5
|
+
*
|
|
6
|
+
* This hook allows users to click and drag to scroll an element, with momentum scrolling
|
|
7
|
+
* that continues after the drag ends. The drag only activates after moving beyond a threshold
|
|
8
|
+
* distance, which prevents accidental drags from clicks.
|
|
9
|
+
*
|
|
10
|
+
* @param element - The HTML element to enable drag to scroll on.
|
|
11
|
+
* @param options - Options for customizing the drag-to-scroll behavior.
|
|
12
|
+
*/
|
|
13
|
+
function useDragToScroll(element, options = {}) {
|
|
14
|
+
const { enabled, decay = 0.95, minVelocity = 0.5, dragThreshold = 5, } = options;
|
|
15
|
+
const stateRef = useRef({
|
|
16
|
+
isDragging: false,
|
|
17
|
+
isPointerActive: false,
|
|
18
|
+
prevX: 0,
|
|
19
|
+
prevY: 0,
|
|
20
|
+
velocityX: 0,
|
|
21
|
+
velocityY: 0,
|
|
22
|
+
rafId: 0,
|
|
23
|
+
startX: 0,
|
|
24
|
+
startY: 0,
|
|
25
|
+
});
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!element || !enabled)
|
|
28
|
+
return;
|
|
29
|
+
const state = stateRef.current;
|
|
30
|
+
const stopMomentum = () => {
|
|
31
|
+
if (state.rafId) {
|
|
32
|
+
cancelAnimationFrame(state.rafId);
|
|
33
|
+
state.rafId = 0;
|
|
34
|
+
}
|
|
35
|
+
state.velocityX = 0;
|
|
36
|
+
state.velocityY = 0;
|
|
37
|
+
};
|
|
38
|
+
const momentumStep = () => {
|
|
39
|
+
state.velocityX *= decay;
|
|
40
|
+
state.velocityY *= decay;
|
|
41
|
+
element.scrollLeft -= state.velocityX;
|
|
42
|
+
element.scrollTop -= state.velocityY;
|
|
43
|
+
if (Math.abs(state.velocityX) < minVelocity &&
|
|
44
|
+
Math.abs(state.velocityY) < minVelocity) {
|
|
45
|
+
state.rafId = 0;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
state.rafId = requestAnimationFrame(momentumStep);
|
|
49
|
+
};
|
|
50
|
+
const onPointerDown = (e) => {
|
|
51
|
+
if (e.pointerType !== 'mouse')
|
|
52
|
+
return;
|
|
53
|
+
stopMomentum();
|
|
54
|
+
state.isDragging = false;
|
|
55
|
+
state.isPointerActive = true;
|
|
56
|
+
state.prevX = e.clientX;
|
|
57
|
+
state.prevY = e.clientY;
|
|
58
|
+
state.startX = e.clientX;
|
|
59
|
+
state.startY = e.clientY;
|
|
60
|
+
};
|
|
61
|
+
const onPointerMove = (e) => {
|
|
62
|
+
if (e.pointerType !== 'mouse')
|
|
63
|
+
return;
|
|
64
|
+
if (!state.isPointerActive)
|
|
65
|
+
return;
|
|
66
|
+
const dx = e.clientX - state.startX;
|
|
67
|
+
const dy = e.clientY - state.startY;
|
|
68
|
+
if (!state.isDragging && Math.hypot(dx, dy) > dragThreshold) {
|
|
69
|
+
state.isDragging = true;
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
}
|
|
72
|
+
if (!state.isDragging)
|
|
73
|
+
return;
|
|
74
|
+
const moveDx = e.clientX - state.prevX;
|
|
75
|
+
const moveDy = e.clientY - state.prevY;
|
|
76
|
+
element.scrollLeft -= moveDx;
|
|
77
|
+
element.scrollTop -= moveDy;
|
|
78
|
+
state.velocityX = moveDx;
|
|
79
|
+
state.velocityY = moveDy;
|
|
80
|
+
state.prevX = e.clientX;
|
|
81
|
+
state.prevY = e.clientY;
|
|
82
|
+
};
|
|
83
|
+
const onPointerUpOrCancel = () => {
|
|
84
|
+
const wasDragging = state.isDragging;
|
|
85
|
+
state.isDragging = false;
|
|
86
|
+
state.isPointerActive = false;
|
|
87
|
+
state.prevX = 0;
|
|
88
|
+
state.prevY = 0;
|
|
89
|
+
state.startX = 0;
|
|
90
|
+
state.startY = 0;
|
|
91
|
+
if (!wasDragging) {
|
|
92
|
+
stopMomentum();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (Math.hypot(state.velocityX, state.velocityY) < minVelocity) {
|
|
96
|
+
stopMomentum();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
state.rafId = requestAnimationFrame(momentumStep);
|
|
100
|
+
};
|
|
101
|
+
element.addEventListener('pointerdown', onPointerDown);
|
|
102
|
+
element.addEventListener('pointermove', onPointerMove);
|
|
103
|
+
window.addEventListener('pointerup', onPointerUpOrCancel);
|
|
104
|
+
window.addEventListener('pointercancel', onPointerUpOrCancel);
|
|
105
|
+
return () => {
|
|
106
|
+
element.removeEventListener('pointerdown', onPointerDown);
|
|
107
|
+
element.removeEventListener('pointermove', onPointerMove);
|
|
108
|
+
window.removeEventListener('pointerup', onPointerUpOrCancel);
|
|
109
|
+
window.removeEventListener('pointercancel', onPointerUpOrCancel);
|
|
110
|
+
stopMomentum();
|
|
111
|
+
};
|
|
112
|
+
}, [element, enabled, decay, minVelocity, dragThreshold]);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export { useDragToScroll };
|
|
116
|
+
//# sourceMappingURL=useDragToScroll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDragToScroll.js","sources":["../../../../../../src/hooks/useDragToScroll.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\ninterface DragScrollState {\n isDragging: boolean;\n isPointerActive: boolean;\n prevX: number;\n prevY: number;\n velocityX: number;\n velocityY: number;\n rafId: number;\n startX: number;\n startY: number;\n}\n\ninterface DragToScrollOptions {\n decay?: number;\n minVelocity?: number;\n dragThreshold?: number;\n enabled?: boolean;\n}\n\n/**\n * Enables drag-to-scroll functionality with momentum scrolling on a scrollable element.\n *\n * This hook allows users to click and drag to scroll an element, with momentum scrolling\n * that continues after the drag ends. The drag only activates after moving beyond a threshold\n * distance, which prevents accidental drags from clicks.\n *\n * @param element - The HTML element to enable drag to scroll on.\n * @param options - Options for customizing the drag-to-scroll behavior.\n */\nexport function useDragToScroll(\n element: HTMLElement | null,\n options: DragToScrollOptions = {},\n) {\n const {\n enabled,\n decay = 0.95,\n minVelocity = 0.5,\n dragThreshold = 5,\n } = options;\n\n const stateRef = useRef<DragScrollState>({\n isDragging: false,\n isPointerActive: false,\n prevX: 0,\n prevY: 0,\n velocityX: 0,\n velocityY: 0,\n rafId: 0,\n startX: 0,\n startY: 0,\n });\n\n useEffect(() => {\n if (!element || !enabled) return;\n\n const state = stateRef.current;\n\n const stopMomentum = () => {\n if (state.rafId) {\n cancelAnimationFrame(state.rafId);\n state.rafId = 0;\n }\n state.velocityX = 0;\n state.velocityY = 0;\n };\n\n const momentumStep = () => {\n state.velocityX *= decay;\n state.velocityY *= decay;\n\n element.scrollLeft -= state.velocityX;\n element.scrollTop -= state.velocityY;\n\n if (\n Math.abs(state.velocityX) < minVelocity &&\n Math.abs(state.velocityY) < minVelocity\n ) {\n state.rafId = 0;\n return;\n }\n\n state.rafId = requestAnimationFrame(momentumStep);\n };\n\n const onPointerDown = (e: PointerEvent) => {\n if (e.pointerType !== 'mouse') return;\n\n stopMomentum();\n\n state.isDragging = false;\n state.isPointerActive = true;\n\n state.prevX = e.clientX;\n state.prevY = e.clientY;\n state.startX = e.clientX;\n state.startY = e.clientY;\n };\n\n const onPointerMove = (e: PointerEvent) => {\n if (e.pointerType !== 'mouse') return;\n\n if (!state.isPointerActive) return;\n\n const dx = e.clientX - state.startX;\n const dy = e.clientY - state.startY;\n\n if (!state.isDragging && Math.hypot(dx, dy) > dragThreshold) {\n state.isDragging = true;\n e.preventDefault();\n }\n\n if (!state.isDragging) return;\n\n const moveDx = e.clientX - state.prevX;\n const moveDy = e.clientY - state.prevY;\n\n element.scrollLeft -= moveDx;\n element.scrollTop -= moveDy;\n\n state.velocityX = moveDx;\n state.velocityY = moveDy;\n\n state.prevX = e.clientX;\n state.prevY = e.clientY;\n };\n\n const onPointerUpOrCancel = () => {\n const wasDragging = state.isDragging;\n\n state.isDragging = false;\n state.isPointerActive = false;\n\n state.prevX = 0;\n state.prevY = 0;\n state.startX = 0;\n state.startY = 0;\n\n if (!wasDragging) {\n stopMomentum();\n return;\n }\n\n if (Math.hypot(state.velocityX, state.velocityY) < minVelocity) {\n stopMomentum();\n return;\n }\n\n state.rafId = requestAnimationFrame(momentumStep);\n };\n\n element.addEventListener('pointerdown', onPointerDown);\n element.addEventListener('pointermove', onPointerMove);\n window.addEventListener('pointerup', onPointerUpOrCancel);\n window.addEventListener('pointercancel', onPointerUpOrCancel);\n\n return () => {\n element.removeEventListener('pointerdown', onPointerDown);\n element.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerup', onPointerUpOrCancel);\n window.removeEventListener('pointercancel', onPointerUpOrCancel);\n\n stopMomentum();\n };\n }, [element, enabled, decay, minVelocity, dragThreshold]);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useFloating, offset, shift, flip, size, autoUpdate } from '@floating-ui/react';
|
|
3
|
+
|
|
4
|
+
const useFloatingUIPreset = ({ middleware = [], placement, strategy, offset: offsetInPx = 10, }) => {
|
|
5
|
+
const { refs, x, y, update, elements: { domReference, floating }, context, } = useFloating({
|
|
6
|
+
placement,
|
|
7
|
+
strategy,
|
|
8
|
+
middleware: [
|
|
9
|
+
offset(offsetInPx),
|
|
10
|
+
shift(),
|
|
11
|
+
flip(),
|
|
12
|
+
size({
|
|
13
|
+
padding: 10,
|
|
14
|
+
apply: ({ availableHeight, elements }) => {
|
|
15
|
+
Object.assign(elements.floating.style, {
|
|
16
|
+
maxHeight: `${availableHeight}px`,
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
}),
|
|
20
|
+
...middleware,
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
// handle window resizing
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!domReference || !floating)
|
|
26
|
+
return;
|
|
27
|
+
const cleanup = autoUpdate(domReference, floating, update);
|
|
28
|
+
return () => cleanup();
|
|
29
|
+
}, [domReference, floating, update]);
|
|
30
|
+
return { refs, x, y, domReference, floating, strategy, context };
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { useFloatingUIPreset };
|
|
34
|
+
//# sourceMappingURL=useFloatingUIPreset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFloatingUIPreset.js","sources":["../../../../../../src/hooks/useFloatingUIPreset.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport type { UseFloatingOptions } from '@floating-ui/react';\nimport {\n autoUpdate,\n flip,\n offset,\n shift,\n size,\n useFloating,\n} from '@floating-ui/react';\n\nexport const useFloatingUIPreset = ({\n middleware = [],\n placement,\n strategy,\n offset: offsetInPx = 10,\n}: Pick<UseFloatingOptions, 'placement' | 'strategy' | 'middleware'> & {\n offset?: number;\n}) => {\n const {\n refs,\n x,\n y,\n update,\n elements: { domReference, floating },\n context,\n } = useFloating({\n placement,\n strategy,\n middleware: [\n offset(offsetInPx),\n shift(),\n flip(),\n size({\n padding: 10,\n apply: ({ availableHeight, elements }) => {\n Object.assign(elements.floating.style, {\n maxHeight: `${availableHeight}px`,\n });\n },\n }),\n ...middleware,\n ],\n });\n\n // handle window resizing\n useEffect(() => {\n if (!domReference || !floating) return;\n\n const cleanup = autoUpdate(domReference, floating, update);\n\n return () => cleanup();\n }, [domReference, floating, update]);\n\n return { refs, x, y, domReference, floating, strategy, context };\n};\n"],"names":[],"mappings":";;;MAWa,mBAAmB,GAAG,CAAC,EAClC,UAAU,GAAG,EAAE,EACf,SAAS,EACT,QAAQ,EACR,MAAM,EAAE,UAAU,GAAG,EAAE,GAGxB,KAAI;IACH,MAAM,EACJ,IAAI,EACJ,CAAC,EACD,CAAC,EACD,MAAM,EACN,QAAQ,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,EACpC,OAAO,GACR,GAAG,WAAW,CAAC;QACd,SAAS;QACT,QAAQ;AACR,QAAA,UAAU,EAAE;YACV,MAAM,CAAC,UAAU,CAAC;AAClB,YAAA,KAAK,EAAE;AACP,YAAA,IAAI,EAAE;AACN,YAAA,IAAI,CAAC;AACH,gBAAA,OAAO,EAAE,EAAE;gBACX,KAAK,EAAE,CAAC,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAI;oBACvC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE;wBACrC,SAAS,EAAE,CAAA,EAAG,eAAe,CAAA,EAAA,CAAI;AAClC,qBAAA,CAAC;gBACJ,CAAC;aACF,CAAC;AACF,YAAA,GAAG,UAAU;AACd,SAAA;AACF,KAAA,CAAC;;IAGF,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,YAAY,IAAI,CAAC,QAAQ;YAAE;QAEhC,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,EAAE,QAAQ,EAAE,MAAM,CAAC;AAE1D,QAAA,OAAO,MAAM,OAAO,EAAE;IACxB,CAAC,EAAE,CAAC,YAAY,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AAEpC,IAAA,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE;AAClE;;;;"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { useState, useRef, useMemo, useCallback, useEffect } from 'react';
|
|
2
|
+
import { getLoopbackStreams, videoLoggerSystem, DEFAULT_LOOPBACK_RECORDING_DURATION_MS, CallingState, waitForLoopbackStreams, LOOPBACK_STREAMS_WAIT_TIMEOUT_MS, enableLoopbackAudio, MediaStreamRecorder, clampLoopbackRecordingDuration } from '@stream-io/video-client';
|
|
3
|
+
import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
4
|
+
|
|
5
|
+
const attachHiddenMediaSink = (stream) => {
|
|
6
|
+
const logger = videoLoggerSystem.getLogger('useLoopbackRecording');
|
|
7
|
+
const element = document.createElement('video');
|
|
8
|
+
element.muted = true;
|
|
9
|
+
element.autoplay = true;
|
|
10
|
+
element.playsInline = true;
|
|
11
|
+
element.srcObject = stream;
|
|
12
|
+
element.play().catch((error) => {
|
|
13
|
+
logger.warn('sink element failed to play; recording may be empty', error);
|
|
14
|
+
});
|
|
15
|
+
return () => {
|
|
16
|
+
element.pause();
|
|
17
|
+
element.srcObject = null;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/** Records SFU loopback streams for pre-call testing. */
|
|
21
|
+
const useLoopbackRecording = () => {
|
|
22
|
+
const call = useCall();
|
|
23
|
+
const { useCallCallingState, useParticipantCount, useLocalParticipant } = useCallStateHooks();
|
|
24
|
+
const callingState = useCallCallingState();
|
|
25
|
+
const participantCount = useParticipantCount();
|
|
26
|
+
const localParticipant = useLocalParticipant();
|
|
27
|
+
const [recordingState, setRecordingState] = useState('idle');
|
|
28
|
+
const recordingStateRef = useRef('idle');
|
|
29
|
+
const isMountedRef = useRef(true);
|
|
30
|
+
const awaitAbortRef = useRef(null);
|
|
31
|
+
const stopRef = useRef(null);
|
|
32
|
+
const runRef = useRef(null);
|
|
33
|
+
const loopbackStreams = useMemo(() => getLoopbackStreams(call, localParticipant), [call, localParticipant]);
|
|
34
|
+
const updateState = useCallback((next) => {
|
|
35
|
+
recordingStateRef.current = next;
|
|
36
|
+
if (isMountedRef.current) {
|
|
37
|
+
setRecordingState(next);
|
|
38
|
+
}
|
|
39
|
+
}, []);
|
|
40
|
+
const stopRecording = useCallback(async () => {
|
|
41
|
+
const current = recordingStateRef.current;
|
|
42
|
+
if (current === 'idle')
|
|
43
|
+
return;
|
|
44
|
+
if (current === 'awaiting-streams') {
|
|
45
|
+
videoLoggerSystem
|
|
46
|
+
.getLogger('useLoopbackRecording')
|
|
47
|
+
.debug('aborting the awaiting-streams wait');
|
|
48
|
+
awaitAbortRef.current?.abort();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
stopRef.current?.();
|
|
52
|
+
await runRef.current;
|
|
53
|
+
}, []);
|
|
54
|
+
const startRecording = useCallback(async ({ includeVideo = true, maxDurationMs = DEFAULT_LOOPBACK_RECORDING_DURATION_MS, } = {}) => {
|
|
55
|
+
const logger = videoLoggerSystem.getLogger('useLoopbackRecording');
|
|
56
|
+
if (!call)
|
|
57
|
+
return null;
|
|
58
|
+
if (recordingStateRef.current !== 'idle') {
|
|
59
|
+
logger.warn('a recording is already running');
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (call.state.participantCount > 1) {
|
|
63
|
+
logger.warn('cannot start recording with other participants present');
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const run = async () => {
|
|
67
|
+
awaitAbortRef.current = new AbortController();
|
|
68
|
+
updateState('awaiting-streams');
|
|
69
|
+
try {
|
|
70
|
+
const tracks = await waitForLoopbackStreams(call, {
|
|
71
|
+
includeVideo,
|
|
72
|
+
signal: awaitAbortRef.current.signal,
|
|
73
|
+
timeoutMs: LOOPBACK_STREAMS_WAIT_TIMEOUT_MS,
|
|
74
|
+
});
|
|
75
|
+
if (tracks === null) {
|
|
76
|
+
logger.debug('loopback stream wait was aborted');
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
updateState('recording');
|
|
80
|
+
const restoreAudio = enableLoopbackAudio(tracks);
|
|
81
|
+
const stream = new MediaStream([tracks.audioTrack, tracks.videoTrack].filter((track) => !!track));
|
|
82
|
+
const detachSink = attachHiddenMediaSink(stream);
|
|
83
|
+
const recorder = new MediaStreamRecorder(stream, {
|
|
84
|
+
maxDurationMs: clampLoopbackRecordingDuration(maxDurationMs),
|
|
85
|
+
});
|
|
86
|
+
stopRef.current = recorder.stop;
|
|
87
|
+
try {
|
|
88
|
+
return await recorder.start();
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
detachSink();
|
|
92
|
+
restoreAudio();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
logger.error('loopback recording failed', err);
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
awaitAbortRef.current = null;
|
|
101
|
+
stopRef.current = null;
|
|
102
|
+
updateState('idle');
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const promise = run();
|
|
106
|
+
runRef.current = promise.catch(() => undefined);
|
|
107
|
+
return promise;
|
|
108
|
+
}, [call, updateState]);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (callingState === CallingState.LEFT ||
|
|
111
|
+
callingState === CallingState.IDLE) {
|
|
112
|
+
stopRecording().catch(() => { });
|
|
113
|
+
}
|
|
114
|
+
}, [callingState, stopRecording]);
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (recordingState !== 'idle' && participantCount > 1) {
|
|
117
|
+
stopRecording().catch(() => { });
|
|
118
|
+
}
|
|
119
|
+
}, [participantCount, recordingState, stopRecording]);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
isMountedRef.current = true;
|
|
122
|
+
return () => {
|
|
123
|
+
isMountedRef.current = false;
|
|
124
|
+
awaitAbortRef.current?.abort('the component unmounted');
|
|
125
|
+
stopRef.current?.();
|
|
126
|
+
};
|
|
127
|
+
}, []);
|
|
128
|
+
return {
|
|
129
|
+
startRecording,
|
|
130
|
+
stopRecording,
|
|
131
|
+
recordingState,
|
|
132
|
+
loopbackVideoStream: loopbackStreams.loopbackVideoStream,
|
|
133
|
+
loopbackAudioStream: loopbackStreams.loopbackAudioStream,
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export { useLoopbackRecording };
|
|
138
|
+
//# sourceMappingURL=useLoopbackRecording.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLoopbackRecording.js","sources":["../../../../../../src/hooks/useLoopbackRecording.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n CallingState,\n DEFAULT_LOOPBACK_RECORDING_DURATION_MS,\n LOOPBACK_STREAMS_WAIT_TIMEOUT_MS,\n MediaStreamRecorder,\n clampLoopbackRecordingDuration,\n getLoopbackStreams,\n type MediaRecordingResult,\n videoLoggerSystem,\n waitForLoopbackStreams,\n enableLoopbackAudio,\n type LoopbackStreams,\n} from '@stream-io/video-client';\nimport { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';\n\n/** Lifecycle phase of a loopback recording. */\nexport type LoopbackRecordingState = 'idle' | 'awaiting-streams' | 'recording';\n\nconst attachHiddenMediaSink = (stream: MediaStream): (() => void) => {\n const logger = videoLoggerSystem.getLogger('useLoopbackRecording');\n const element = document.createElement('video');\n element.muted = true;\n element.autoplay = true;\n element.playsInline = true;\n element.srcObject = stream;\n\n element.play().catch((error) => {\n logger.warn('sink element failed to play; recording may be empty', error);\n });\n\n return () => {\n element.pause();\n element.srcObject = null;\n };\n};\n\nexport type StartLoopbackRecordingOptions = {\n /** Whether to include loopback video. Audio is always recorded. */\n includeVideo?: boolean;\n /** Maximum recording duration in milliseconds. */\n maxDurationMs?: number;\n};\n\nexport type UseLoopbackRecordingResult = {\n /** Starts recording and resolves with the recorded blob. */\n startRecording: (\n options?: StartLoopbackRecordingOptions,\n ) => Promise<MediaRecordingResult | null>;\n /** Stops the current recording or stream wait. */\n stopRecording: () => Promise<void>;\n /** Lifecycle phase of the recording. */\n recordingState: LoopbackRecordingState;\n /** SFU-echoed video stream on the local participant. */\n loopbackVideoStream?: MediaStream;\n /** SFU-echoed audio stream on the local participant. */\n loopbackAudioStream?: MediaStream;\n};\n\n/** Records SFU loopback streams for pre-call testing. */\nexport const useLoopbackRecording = (): UseLoopbackRecordingResult => {\n const call = useCall();\n const { useCallCallingState, useParticipantCount, useLocalParticipant } =\n useCallStateHooks();\n const callingState = useCallCallingState();\n const participantCount = useParticipantCount();\n const localParticipant = useLocalParticipant();\n\n const [recordingState, setRecordingState] =\n useState<LoopbackRecordingState>('idle');\n\n const recordingStateRef = useRef<LoopbackRecordingState>('idle');\n const isMountedRef = useRef(true);\n const awaitAbortRef = useRef<AbortController | null>(null);\n const stopRef = useRef<(() => void) | null>(null);\n const runRef = useRef<Promise<unknown> | null>(null);\n\n const loopbackStreams = useMemo<LoopbackStreams>(\n () => getLoopbackStreams(call, localParticipant),\n [call, localParticipant],\n );\n\n const updateState = useCallback((next: LoopbackRecordingState) => {\n recordingStateRef.current = next;\n if (isMountedRef.current) {\n setRecordingState(next);\n }\n }, []);\n\n const stopRecording = useCallback(async (): Promise<void> => {\n const current = recordingStateRef.current;\n if (current === 'idle') return;\n\n if (current === 'awaiting-streams') {\n videoLoggerSystem\n .getLogger('useLoopbackRecording')\n .debug('aborting the awaiting-streams wait');\n awaitAbortRef.current?.abort();\n return;\n }\n\n stopRef.current?.();\n await runRef.current;\n }, []);\n\n const startRecording = useCallback(\n async ({\n includeVideo = true,\n maxDurationMs = DEFAULT_LOOPBACK_RECORDING_DURATION_MS,\n }: StartLoopbackRecordingOptions = {}): Promise<MediaRecordingResult | null> => {\n const logger = videoLoggerSystem.getLogger('useLoopbackRecording');\n if (!call) return null;\n\n if (recordingStateRef.current !== 'idle') {\n logger.warn('a recording is already running');\n return null;\n }\n\n if (call.state.participantCount > 1) {\n logger.warn('cannot start recording with other participants present');\n return null;\n }\n\n const run = async (): Promise<MediaRecordingResult | null> => {\n awaitAbortRef.current = new AbortController();\n updateState('awaiting-streams');\n\n try {\n const tracks = await waitForLoopbackStreams(call, {\n includeVideo,\n signal: awaitAbortRef.current.signal,\n timeoutMs: LOOPBACK_STREAMS_WAIT_TIMEOUT_MS,\n });\n\n if (tracks === null) {\n logger.debug('loopback stream wait was aborted');\n return null;\n }\n\n updateState('recording');\n\n const restoreAudio = enableLoopbackAudio(tracks);\n const stream = new MediaStream(\n [tracks.audioTrack, tracks.videoTrack].filter(\n (track): track is MediaStreamTrack => !!track,\n ),\n );\n const detachSink = attachHiddenMediaSink(stream);\n const recorder = new MediaStreamRecorder(stream, {\n maxDurationMs: clampLoopbackRecordingDuration(maxDurationMs),\n });\n stopRef.current = recorder.stop;\n try {\n return await recorder.start();\n } finally {\n detachSink();\n restoreAudio();\n }\n } catch (err) {\n logger.error('loopback recording failed', err);\n throw err;\n } finally {\n awaitAbortRef.current = null;\n stopRef.current = null;\n updateState('idle');\n }\n };\n\n const promise = run();\n runRef.current = promise.catch(() => undefined);\n return promise;\n },\n [call, updateState],\n );\n\n useEffect(() => {\n if (\n callingState === CallingState.LEFT ||\n callingState === CallingState.IDLE\n ) {\n stopRecording().catch(() => {});\n }\n }, [callingState, stopRecording]);\n\n useEffect(() => {\n if (recordingState !== 'idle' && participantCount > 1) {\n stopRecording().catch(() => {});\n }\n }, [participantCount, recordingState, stopRecording]);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n awaitAbortRef.current?.abort('the component unmounted');\n stopRef.current?.();\n };\n }, []);\n\n return {\n startRecording,\n stopRecording,\n recordingState,\n loopbackVideoStream: loopbackStreams.loopbackVideoStream,\n loopbackAudioStream: loopbackStreams.loopbackAudioStream,\n };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { useRef, useCallback, useEffect } from 'react';
|
|
2
|
+
import { useCall } from '@stream-io/video-react-bindings';
|
|
3
|
+
|
|
4
|
+
const isFullScreenBlurPlatformSupported = () => {
|
|
5
|
+
if (typeof window === 'undefined' ||
|
|
6
|
+
typeof OffscreenCanvas === 'undefined' ||
|
|
7
|
+
typeof VideoFrame === 'undefined' ||
|
|
8
|
+
!window.WebGL2RenderingContext) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const canvas = new OffscreenCanvas(1, 1);
|
|
13
|
+
return !!canvas.getContext('webgl2', {
|
|
14
|
+
alpha: false,
|
|
15
|
+
antialias: false,
|
|
16
|
+
desynchronized: true,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const useModeration = (options) => {
|
|
24
|
+
const { duration = 5000 } = options || {};
|
|
25
|
+
const call = useCall();
|
|
26
|
+
const timeoutRef = useRef(null);
|
|
27
|
+
const processorRef = useRef(null);
|
|
28
|
+
const unregisterRef = useRef(null);
|
|
29
|
+
const blurModulePromise = useRef(null);
|
|
30
|
+
/**
|
|
31
|
+
* Lazily loads and caches the video-filters-web module.
|
|
32
|
+
*/
|
|
33
|
+
const loadVideoFiltersWebModule = useCallback(() => {
|
|
34
|
+
if (!blurModulePromise.current) {
|
|
35
|
+
blurModulePromise.current = import('@stream-io/video-filters-web')
|
|
36
|
+
.then((module) => module.FullScreenBlur)
|
|
37
|
+
.catch((error) => {
|
|
38
|
+
console.error('[moderation] Failed to import blur module:', error);
|
|
39
|
+
throw error;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return blurModulePromise.current;
|
|
43
|
+
}, []);
|
|
44
|
+
const disableBlur = useCallback(() => {
|
|
45
|
+
if (timeoutRef.current) {
|
|
46
|
+
clearTimeout(timeoutRef.current);
|
|
47
|
+
timeoutRef.current = null;
|
|
48
|
+
}
|
|
49
|
+
unregisterRef
|
|
50
|
+
.current?.()
|
|
51
|
+
.catch((err) => console.error('[moderation] unregister error:', err));
|
|
52
|
+
unregisterRef.current = null;
|
|
53
|
+
}, []);
|
|
54
|
+
const handleFallback = useCallback(async () => {
|
|
55
|
+
try {
|
|
56
|
+
await call?.camera.disable();
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
console.error('[moderation] Failed to disable camera:', error);
|
|
60
|
+
}
|
|
61
|
+
}, [call]);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (!call)
|
|
64
|
+
return;
|
|
65
|
+
return call.on('call.moderation_warning', async () => {
|
|
66
|
+
try {
|
|
67
|
+
await loadVideoFiltersWebModule();
|
|
68
|
+
}
|
|
69
|
+
catch (importErr) {
|
|
70
|
+
console.error('[moderation] Failed to import blur module:', importErr);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}, [call, loadVideoFiltersWebModule]);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (!call)
|
|
76
|
+
return;
|
|
77
|
+
return call.on('call.moderation_blur', async () => {
|
|
78
|
+
if (unregisterRef.current)
|
|
79
|
+
return;
|
|
80
|
+
let FullScreenBlurClass;
|
|
81
|
+
try {
|
|
82
|
+
FullScreenBlurClass = await loadVideoFiltersWebModule();
|
|
83
|
+
}
|
|
84
|
+
catch (importErr) {
|
|
85
|
+
console.error('[moderation] Failed to import blur module:', importErr);
|
|
86
|
+
await handleFallback();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (!isFullScreenBlurPlatformSupported()) {
|
|
90
|
+
console.warn('[moderation] Blur not supported on this platform');
|
|
91
|
+
await handleFallback();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const { unregister } = call.camera.registerFilter((inputStream) => {
|
|
95
|
+
unregisterRef.current = unregister;
|
|
96
|
+
const outputPromise = new Promise(async (resolve, reject) => {
|
|
97
|
+
const [track] = inputStream.getVideoTracks();
|
|
98
|
+
let processor;
|
|
99
|
+
try {
|
|
100
|
+
processor = new FullScreenBlurClass(track);
|
|
101
|
+
processorRef.current = processor;
|
|
102
|
+
const result = await processor.start();
|
|
103
|
+
const output = new MediaStream([result]);
|
|
104
|
+
resolve(output);
|
|
105
|
+
if (duration > 0) {
|
|
106
|
+
timeoutRef.current = setTimeout(disableBlur, duration);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
reject(error);
|
|
111
|
+
console.error('[moderation] Processor init failed:', error);
|
|
112
|
+
await unregisterRef.current?.();
|
|
113
|
+
unregisterRef.current = null;
|
|
114
|
+
processorRef.current = null;
|
|
115
|
+
await handleFallback();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
output: outputPromise,
|
|
121
|
+
stop: () => {
|
|
122
|
+
if (processorRef.current) {
|
|
123
|
+
processorRef.current.stop();
|
|
124
|
+
processorRef.current = null;
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}, [call, loadVideoFiltersWebModule, disableBlur, handleFallback, duration]);
|
|
131
|
+
useEffect(() => disableBlur, [disableBlur]);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export { useModeration };
|
|
135
|
+
//# sourceMappingURL=useModeration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useModeration.js","sources":["../../../../../../src/hooks/useModeration.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { useCall } from '@stream-io/video-react-bindings';\n\ntype FullScreenBlurType =\n typeof import('@stream-io/video-filters-web').FullScreenBlur;\n\nconst isFullScreenBlurPlatformSupported = (): boolean => {\n if (\n typeof window === 'undefined' ||\n typeof OffscreenCanvas === 'undefined' ||\n typeof VideoFrame === 'undefined' ||\n !window.WebGL2RenderingContext\n ) {\n return false;\n }\n\n try {\n const canvas = new OffscreenCanvas(1, 1);\n return !!canvas.getContext('webgl2', {\n alpha: false,\n antialias: false,\n desynchronized: true,\n });\n } catch {\n return false;\n }\n};\n\nexport interface ModerationOptions {\n /**\n * How long the moderation effect should stay active before being disabled.\n * Set to `0` to keep it active indefinitely. Defaults to 5000 ms.\n */\n duration?: number;\n}\n\nexport const useModeration = (options?: ModerationOptions) => {\n const { duration = 5000 } = options || {};\n\n const call = useCall();\n\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const processorRef = useRef<InstanceType<FullScreenBlurType> | null>(null);\n const unregisterRef = useRef<(() => Promise<void>) | null>(null);\n\n const blurModulePromise = useRef<Promise<FullScreenBlurType> | null>(null);\n\n /**\n * Lazily loads and caches the video-filters-web module.\n */\n const loadVideoFiltersWebModule = useCallback(() => {\n if (!blurModulePromise.current) {\n blurModulePromise.current = import('@stream-io/video-filters-web')\n .then((module) => module.FullScreenBlur)\n .catch((error) => {\n console.error('[moderation] Failed to import blur module:', error);\n throw error;\n });\n }\n\n return blurModulePromise.current;\n }, []);\n\n const disableBlur = useCallback(() => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n\n unregisterRef\n .current?.()\n .catch((err) => console.error('[moderation] unregister error:', err));\n\n unregisterRef.current = null;\n }, []);\n\n const handleFallback = useCallback(async () => {\n try {\n await call?.camera.disable();\n } catch (error) {\n console.error('[moderation] Failed to disable camera:', error);\n }\n }, [call]);\n\n useEffect(() => {\n if (!call) return;\n\n return call.on('call.moderation_warning', async () => {\n try {\n await loadVideoFiltersWebModule();\n } catch (importErr) {\n console.error('[moderation] Failed to import blur module:', importErr);\n }\n });\n }, [call, loadVideoFiltersWebModule]);\n\n useEffect(() => {\n if (!call) return;\n\n return call.on('call.moderation_blur', async () => {\n if (unregisterRef.current) return;\n\n let FullScreenBlurClass: FullScreenBlurType;\n\n try {\n FullScreenBlurClass = await loadVideoFiltersWebModule();\n } catch (importErr) {\n console.error('[moderation] Failed to import blur module:', importErr);\n await handleFallback();\n return;\n }\n\n if (!isFullScreenBlurPlatformSupported()) {\n console.warn('[moderation] Blur not supported on this platform');\n await handleFallback();\n return;\n }\n\n const { unregister } = call.camera.registerFilter((inputStream) => {\n unregisterRef.current = unregister;\n\n const outputPromise = new Promise<MediaStream>(\n async (resolve, reject) => {\n const [track] = inputStream.getVideoTracks();\n\n let processor: InstanceType<FullScreenBlurType>;\n\n try {\n processor = new FullScreenBlurClass(track);\n processorRef.current = processor;\n\n const result = await processor.start();\n const output = new MediaStream([result]);\n resolve(output);\n\n if (duration > 0) {\n timeoutRef.current = setTimeout(disableBlur, duration);\n }\n } catch (error) {\n reject(error);\n console.error('[moderation] Processor init failed:', error);\n\n await unregisterRef.current?.();\n unregisterRef.current = null;\n processorRef.current = null;\n\n await handleFallback();\n return;\n }\n },\n );\n\n return {\n output: outputPromise,\n stop: () => {\n if (processorRef.current) {\n processorRef.current.stop();\n processorRef.current = null;\n }\n },\n };\n });\n });\n }, [call, loadVideoFiltersWebModule, disableBlur, handleFallback, duration]);\n\n useEffect(() => disableBlur, [disableBlur]);\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This hook is a no-op. Device preference persistence is now handled
|
|
5
|
+
* by the low-level client SDK.
|
|
6
|
+
*
|
|
7
|
+
* @deprecated use the devicePreferences API of the StreamVideoClient.
|
|
8
|
+
*/
|
|
9
|
+
const usePersistedDevicePreferences = (key = '') => {
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
console.warn(`usePersistedDevicePreferences is deprecated. Please use the devicePreferences API of the StreamVideoClient instead.`);
|
|
12
|
+
}, [key]);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { usePersistedDevicePreferences };
|
|
16
|
+
//# sourceMappingURL=usePersistedDevicePreferences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePersistedDevicePreferences.js","sources":["../../../../../../src/hooks/usePersistedDevicePreferences.ts"],"sourcesContent":["import { useEffect } from 'react';\n\n/**\n * This hook is a no-op. Device preference persistence is now handled\n * by the low-level client SDK.\n *\n * @deprecated use the devicePreferences API of the StreamVideoClient.\n */\nexport const usePersistedDevicePreferences = (key: string = ''): void => {\n useEffect(() => {\n console.warn(\n `usePersistedDevicePreferences is deprecated. Please use the devicePreferences API of the StreamVideoClient instead.`,\n );\n }, [key]);\n};\n"],"names":[],"mappings":";;AAEA;;;;;AAKG;MACU,6BAA6B,GAAG,CAAC,GAAA,GAAc,EAAE,KAAU;IACtE,SAAS,CAAC,MAAK;AACb,QAAA,OAAO,CAAC,IAAI,CACV,CAAA,mHAAA,CAAqH,CACtH;AACH,IAAA,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;AACX;;;;"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
3
|
+
|
|
4
|
+
const useRequestPermission = (permission) => {
|
|
5
|
+
const call = useCall();
|
|
6
|
+
const { useHasPermissions } = useCallStateHooks();
|
|
7
|
+
const hasPermission = useHasPermissions(permission);
|
|
8
|
+
const [isAwaitingPermission, setIsAwaitingPermission] = useState(false); // TODO: load with possibly pending state
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const reset = () => setIsAwaitingPermission(false);
|
|
11
|
+
if (hasPermission)
|
|
12
|
+
reset();
|
|
13
|
+
}, [hasPermission]);
|
|
14
|
+
const requestPermission = useCallback(async () => {
|
|
15
|
+
if (hasPermission)
|
|
16
|
+
return true;
|
|
17
|
+
const canRequestPermission = !!call?.permissionsContext.canRequest(permission);
|
|
18
|
+
if (isAwaitingPermission || !canRequestPermission)
|
|
19
|
+
return false;
|
|
20
|
+
setIsAwaitingPermission(true);
|
|
21
|
+
try {
|
|
22
|
+
await call?.requestPermissions({
|
|
23
|
+
permissions: [permission],
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
setIsAwaitingPermission(false);
|
|
28
|
+
throw new Error(`requestPermission failed: ${error}`);
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}, [call, hasPermission, isAwaitingPermission, permission]);
|
|
32
|
+
return {
|
|
33
|
+
requestPermission,
|
|
34
|
+
hasPermission,
|
|
35
|
+
canRequestPermission: !!call?.permissionsContext.canRequest(permission),
|
|
36
|
+
isAwaitingPermission,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export { useRequestPermission };
|
|
41
|
+
//# sourceMappingURL=useRequestPermission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRequestPermission.js","sources":["../../../../../../src/hooks/useRequestPermission.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport { RequestPermissionRequestPermissionsEnum } from '@stream-io/video-client';\nimport { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';\n\nexport const useRequestPermission = (\n permission: RequestPermissionRequestPermissionsEnum,\n) => {\n const call = useCall();\n const { useHasPermissions } = useCallStateHooks();\n const hasPermission = useHasPermissions(permission);\n const [isAwaitingPermission, setIsAwaitingPermission] = useState(false); // TODO: load with possibly pending state\n\n useEffect(() => {\n const reset = () => setIsAwaitingPermission(false);\n\n if (hasPermission) reset();\n }, [hasPermission]);\n\n const requestPermission = useCallback(async () => {\n if (hasPermission) return true;\n\n const canRequestPermission =\n !!call?.permissionsContext.canRequest(permission);\n if (isAwaitingPermission || !canRequestPermission) return false;\n\n setIsAwaitingPermission(true);\n\n try {\n await call?.requestPermissions({\n permissions: [permission],\n });\n } catch (error) {\n setIsAwaitingPermission(false);\n throw new Error(`requestPermission failed: ${error}`);\n }\n\n return false;\n }, [call, hasPermission, isAwaitingPermission, permission]);\n\n return {\n requestPermission,\n hasPermission,\n canRequestPermission: !!call?.permissionsContext.canRequest(permission),\n isAwaitingPermission,\n };\n};\n"],"names":[],"mappings":";;;AAIO,MAAM,oBAAoB,GAAG,CAClC,UAAmD,KACjD;AACF,IAAA,MAAM,IAAI,GAAG,OAAO,EAAE;AACtB,IAAA,MAAM,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE;AACjD,IAAA,MAAM,aAAa,GAAG,iBAAiB,CAAC,UAAU,CAAC;AACnD,IAAA,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAExE,SAAS,CAAC,MAAK;QACb,MAAM,KAAK,GAAG,MAAM,uBAAuB,CAAC,KAAK,CAAC;AAElD,QAAA,IAAI,aAAa;AAAE,YAAA,KAAK,EAAE;AAC5B,IAAA,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;AAEnB,IAAA,MAAM,iBAAiB,GAAG,WAAW,CAAC,YAAW;AAC/C,QAAA,IAAI,aAAa;AAAE,YAAA,OAAO,IAAI;AAE9B,QAAA,MAAM,oBAAoB,GACxB,CAAC,CAAC,IAAI,EAAE,kBAAkB,CAAC,UAAU,CAAC,UAAU,CAAC;QACnD,IAAI,oBAAoB,IAAI,CAAC,oBAAoB;AAAE,YAAA,OAAO,KAAK;QAE/D,uBAAuB,CAAC,IAAI,CAAC;AAE7B,QAAA,IAAI;YACF,MAAM,IAAI,EAAE,kBAAkB,CAAC;gBAC7B,WAAW,EAAE,CAAC,UAAU,CAAC;AAC1B,aAAA,CAAC;QACJ;QAAE,OAAO,KAAK,EAAE;YACd,uBAAuB,CAAC,KAAK,CAAC;AAC9B,YAAA,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,CAAA,CAAE,CAAC;QACvD;AAEA,QAAA,OAAO,KAAK;IACd,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,oBAAoB,EAAE,UAAU,CAAC,CAAC;IAE3D,OAAO;QACL,iBAAiB;QACjB,aAAa;QACb,oBAAoB,EAAE,CAAC,CAAC,IAAI,EAAE,kBAAkB,CAAC,UAAU,CAAC,UAAU,CAAC;QACvE,oBAAoB;KACrB;AACH;;;;"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
const SCROLL_THRESHOLD = 10;
|
|
4
|
+
/**
|
|
5
|
+
* Hook which observes element's scroll position and returns text value based on the
|
|
6
|
+
* position of the scrollbar (`top`, `bottom`, `between` and `null` if no scrollbar is available)
|
|
7
|
+
*/
|
|
8
|
+
const useVerticalScrollPosition = (scrollElement, threshold = SCROLL_THRESHOLD) => {
|
|
9
|
+
const [scrollPosition, setScrollPosition] = useState(null);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!scrollElement)
|
|
12
|
+
return;
|
|
13
|
+
const scrollHandler = () => {
|
|
14
|
+
const element = scrollElement;
|
|
15
|
+
const hasVerticalScrollbar = element.scrollHeight > element.clientHeight;
|
|
16
|
+
if (!hasVerticalScrollbar)
|
|
17
|
+
return setScrollPosition(null);
|
|
18
|
+
const isAtTheTop = element.scrollTop <= threshold;
|
|
19
|
+
if (isAtTheTop)
|
|
20
|
+
return setScrollPosition('top');
|
|
21
|
+
const isAtTheBottom = Math.abs(element.scrollHeight - element.scrollTop - element.clientHeight) <= threshold;
|
|
22
|
+
if (isAtTheBottom)
|
|
23
|
+
return setScrollPosition('bottom');
|
|
24
|
+
setScrollPosition('between');
|
|
25
|
+
};
|
|
26
|
+
const resizeObserver = new ResizeObserver(scrollHandler);
|
|
27
|
+
resizeObserver.observe(scrollElement);
|
|
28
|
+
scrollElement.addEventListener('scroll', scrollHandler, { passive: true });
|
|
29
|
+
return () => {
|
|
30
|
+
scrollElement.removeEventListener('scroll', scrollHandler);
|
|
31
|
+
resizeObserver.disconnect();
|
|
32
|
+
};
|
|
33
|
+
}, [scrollElement, threshold]);
|
|
34
|
+
return scrollPosition;
|
|
35
|
+
};
|
|
36
|
+
const useHorizontalScrollPosition = (scrollElement, threshold = SCROLL_THRESHOLD) => {
|
|
37
|
+
const [scrollPosition, setScrollPosition] = useState(null);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!scrollElement)
|
|
40
|
+
return;
|
|
41
|
+
const scrollHandler = () => {
|
|
42
|
+
const element = scrollElement;
|
|
43
|
+
const hasHorizontalScrollbar = element.scrollWidth > element.clientWidth;
|
|
44
|
+
if (!hasHorizontalScrollbar)
|
|
45
|
+
return setScrollPosition(null);
|
|
46
|
+
const isAtTheStart = element.scrollLeft <= threshold;
|
|
47
|
+
if (isAtTheStart)
|
|
48
|
+
return setScrollPosition('start');
|
|
49
|
+
const isAtTheEnd = Math.abs(element.scrollWidth - element.scrollLeft - element.clientWidth) <= threshold;
|
|
50
|
+
if (isAtTheEnd)
|
|
51
|
+
return setScrollPosition('end');
|
|
52
|
+
setScrollPosition('between');
|
|
53
|
+
};
|
|
54
|
+
const resizeObserver = new ResizeObserver(scrollHandler);
|
|
55
|
+
resizeObserver.observe(scrollElement);
|
|
56
|
+
scrollElement.addEventListener('scroll', scrollHandler, { passive: true });
|
|
57
|
+
return () => {
|
|
58
|
+
scrollElement.removeEventListener('scroll', scrollHandler);
|
|
59
|
+
resizeObserver.disconnect();
|
|
60
|
+
};
|
|
61
|
+
}, [scrollElement, threshold]);
|
|
62
|
+
return scrollPosition;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export { useHorizontalScrollPosition, useVerticalScrollPosition };
|
|
66
|
+
//# sourceMappingURL=useScrollPosition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScrollPosition.js","sources":["../../../../../../src/hooks/useScrollPosition.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nconst SCROLL_THRESHOLD = 10;\n\n/**\n * Hook which observes element's scroll position and returns text value based on the\n * position of the scrollbar (`top`, `bottom`, `between` and `null` if no scrollbar is available)\n */\nexport const useVerticalScrollPosition = (\n scrollElement: HTMLElement | null,\n threshold: number = SCROLL_THRESHOLD,\n) => {\n const [scrollPosition, setScrollPosition] = useState<\n 'top' | 'bottom' | 'between' | null\n >(null);\n\n useEffect(() => {\n if (!scrollElement) return;\n\n const scrollHandler = () => {\n const element = scrollElement;\n\n const hasVerticalScrollbar = element.scrollHeight > element.clientHeight;\n\n if (!hasVerticalScrollbar) return setScrollPosition(null);\n\n const isAtTheTop = element.scrollTop <= threshold;\n if (isAtTheTop) return setScrollPosition('top');\n\n const isAtTheBottom =\n Math.abs(\n element.scrollHeight - element.scrollTop - element.clientHeight,\n ) <= threshold;\n\n if (isAtTheBottom) return setScrollPosition('bottom');\n\n setScrollPosition('between');\n };\n\n const resizeObserver = new ResizeObserver(scrollHandler);\n resizeObserver.observe(scrollElement);\n\n scrollElement.addEventListener('scroll', scrollHandler, { passive: true });\n return () => {\n scrollElement.removeEventListener('scroll', scrollHandler);\n resizeObserver.disconnect();\n };\n }, [scrollElement, threshold]);\n\n return scrollPosition;\n};\n\nexport const useHorizontalScrollPosition = (\n scrollElement: HTMLElement | null,\n threshold: number = SCROLL_THRESHOLD,\n) => {\n const [scrollPosition, setScrollPosition] = useState<\n 'start' | 'end' | 'between' | null\n >(null);\n\n useEffect(() => {\n if (!scrollElement) return;\n\n const scrollHandler = () => {\n const element = scrollElement;\n\n const hasHorizontalScrollbar = element.scrollWidth > element.clientWidth;\n\n if (!hasHorizontalScrollbar) return setScrollPosition(null);\n\n const isAtTheStart = element.scrollLeft <= threshold;\n if (isAtTheStart) return setScrollPosition('start');\n\n const isAtTheEnd =\n Math.abs(\n element.scrollWidth - element.scrollLeft - element.clientWidth,\n ) <= threshold;\n\n if (isAtTheEnd) return setScrollPosition('end');\n\n setScrollPosition('between');\n };\n\n const resizeObserver = new ResizeObserver(scrollHandler);\n resizeObserver.observe(scrollElement);\n\n scrollElement.addEventListener('scroll', scrollHandler, { passive: true });\n return () => {\n scrollElement.removeEventListener('scroll', scrollHandler);\n resizeObserver.disconnect();\n };\n }, [scrollElement, threshold]);\n\n return scrollPosition;\n};\n"],"names":[],"mappings":"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"}
|