communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
145 lines • 9.11 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import React, { useCallback, useMemo, useRef } from 'react';
import { VideoGallery, Announcer } from "../../../../../react-components/src";
import { _useContainerWidth, _useContainerHeight } from "../../../../../react-components/src";
import { usePropsFor } from '../hooks/usePropsFor';
import { AvatarPersona } from '../../common/AvatarPersona';
import { mergeStyles, Stack } from '@fluentui/react';
import { useHandlers } from '../hooks/useHandlers';
import { useSelector } from '../hooks/useSelector';
import { localVideoCameraCycleButtonSelector } from '../selectors/LocalVideoTileSelector';
import { LocalVideoCameraCycleButton } from "../../../../../react-components/src";
import { useParticipantChangedAnnouncement } from '../utils/MediaGalleryUtils';
import { useLocalSpotlightCallbacksWithPrompt, useRemoteSpotlightCallbacksWithPrompt } from '../utils/spotlightUtils';
import { getCapabilites, getIsRoomsCall, getReactionResources, getRole } from '../selectors/baseSelectors';
const VideoGalleryStyles = {
root: {
height: '100%',
minHeight: '10rem', // space affordance to ensure media gallery is never collapsed
minWidth: '6rem'
}
};
const localVideoViewOptions = {
scalingMode: 'Crop',
isMirrored: true
};
const remoteVideoViewOptions = {
scalingMode: 'Crop'
};
/**
* @private
*/
export const MediaGallery = (props) => {
var _a, _b;
const { pinnedParticipants = [], setPinnedParticipants, setIsPromptOpen, setPromptProps, hideSpotlightButtons, videoTilesOptions, captionsOptions, compositeContainerAspectRatio } = props;
const videoGalleryProps = usePropsFor(VideoGallery);
const cameraSwitcherCameras = useSelector(localVideoCameraCycleButtonSelector);
const cameraSwitcherCallback = useHandlers(LocalVideoCameraCycleButton);
const announcerString = useParticipantChangedAnnouncement();
const userRole = useSelector(getRole);
const capabilities = useSelector(getCapabilites);
const isRoomsCall = useSelector(getIsRoomsCall);
const reactionResources = useSelector(getReactionResources);
const containerRef = useRef(null);
const containerWidth = _useContainerWidth(containerRef);
const containerHeight = _useContainerHeight(containerRef);
const layoutBasedOnTilePosition = getVideoGalleryLayoutBasedOnLocalOptions((_a = props.localVideoTileOptions) === null || _a === void 0 ? void 0 : _a.position);
const cameraSwitcherProps = useMemo(() => {
return Object.assign(Object.assign({}, cameraSwitcherCallback), cameraSwitcherCameras);
}, [cameraSwitcherCallback, cameraSwitcherCameras]);
const onRenderAvatar = useCallback((userId, options) => {
return (React.createElement(Stack, { className: mergeStyles({ position: 'absolute', height: '100%', width: '100%' }) },
React.createElement(Stack, { styles: { root: { margin: 'auto', maxHeight: '100%' } } }, (options === null || options === void 0 ? void 0 : options.coinSize) && (React.createElement(AvatarPersona, Object.assign({ userId: userId }, options, { dataProvider: props.onFetchAvatarPersonaData }))))));
}, [props.onFetchAvatarPersonaData]);
const remoteVideoTileMenuOptions = useMemo(() => {
var _a;
return ((_a = props.remoteVideoTileMenuOptions) === null || _a === void 0 ? void 0 : _a.isHidden)
? false
: props.isMobile
? { kind: 'drawer', hostId: props.drawerMenuHostId }
: { kind: 'contextual' };
}, [(_b = props.remoteVideoTileMenuOptions) === null || _b === void 0 ? void 0 : _b.isHidden, props.isMobile, props.drawerMenuHostId]);
const overflowGalleryPosition = useMemo(() => {
/* @conditional-compile-remove(overflow-top-composite) */
if (props.userSetOverflowGalleryPosition === 'horizontalTop') {
return props.userSetOverflowGalleryPosition;
}
return containerWidth && containerHeight && containerWidth / containerHeight >= 16 / 9
? 'verticalRight'
: 'horizontalBottom';
}, [
/* @conditional-compile-remove(overflow-top-composite) */ props.userSetOverflowGalleryPosition,
containerWidth,
containerHeight
]);
const { onStartLocalSpotlight, onStopLocalSpotlight, onStartRemoteSpotlight, onStopRemoteSpotlight } = videoGalleryProps;
const { onStartLocalSpotlightWithPrompt, onStopLocalSpotlightWithPrompt } = useLocalSpotlightCallbacksWithPrompt(onStartLocalSpotlight, onStopLocalSpotlight, setIsPromptOpen, setPromptProps);
const { onStartRemoteSpotlightWithPrompt, onStopRemoteSpotlightWithPrompt } = useRemoteSpotlightCallbacksWithPrompt(onStartRemoteSpotlight, onStopRemoteSpotlight, setIsPromptOpen, setPromptProps);
const galleryStyles = useMemo(() => {
return Object.assign(Object.assign({}, VideoGalleryStyles), ((captionsOptions === null || captionsOptions === void 0 ? void 0 : captionsOptions.height) === 'full' ? { root: { postion: 'absolute' } } : {}));
}, [captionsOptions === null || captionsOptions === void 0 ? void 0 : captionsOptions.height]);
const onPinParticipant = useMemo(() => {
return setPinnedParticipants
? (userId) => {
if (!pinnedParticipants.includes(userId)) {
setPinnedParticipants(pinnedParticipants.concat(userId));
}
}
: undefined;
}, [setPinnedParticipants, pinnedParticipants]);
const onUnpinParticipant = useMemo(() => {
return setPinnedParticipants
? (userId) => {
setPinnedParticipants(pinnedParticipants.filter((participantId) => participantId !== userId));
}
: undefined;
}, [setPinnedParticipants, pinnedParticipants]);
const VideoGalleryMemoized = useMemo(() => {
var _a;
const layoutBasedOnUserSelection = () => {
return props.localVideoTileOptions ? layoutBasedOnTilePosition : props.userSetGalleryLayout;
};
return (React.createElement(VideoGallery, Object.assign({}, videoGalleryProps, { videoTilesOptions: videoTilesOptions, localVideoViewOptions: localVideoViewOptions, remoteVideoViewOptions: remoteVideoViewOptions, styles: galleryStyles, layout: layoutBasedOnUserSelection(), showCameraSwitcherInLocalPreview: props.isMobile, localVideoCameraCycleButtonProps: cameraSwitcherProps, onRenderAvatar: onRenderAvatar, remoteVideoTileMenu: remoteVideoTileMenuOptions, overflowGalleryPosition: overflowGalleryPosition, localVideoTileSize: props.localVideoTileOptions === false || userRole === 'Consumer' || (isRoomsCall && userRole === 'Unknown')
? 'hidden'
: props.isMobile && compositeContainerAspectRatio && compositeContainerAspectRatio < 1
? '9:16'
: '16:9', pinnedParticipants: pinnedParticipants, onPinParticipant: onPinParticipant, onUnpinParticipant: onUnpinParticipant, reactionResources: reactionResources, onStartLocalSpotlight: hideSpotlightButtons ? undefined : onStartLocalSpotlightWithPrompt, onStopLocalSpotlight: hideSpotlightButtons ? undefined : onStopLocalSpotlightWithPrompt, onStartRemoteSpotlight: hideSpotlightButtons ? undefined : onStartRemoteSpotlightWithPrompt, onStopRemoteSpotlight: hideSpotlightButtons ? undefined : onStopRemoteSpotlightWithPrompt, onMuteParticipant: ((_a = capabilities === null || capabilities === void 0 ? void 0 : capabilities.muteOthers) === null || _a === void 0 ? void 0 : _a.isPresent) || userRole === 'Unknown'
? videoGalleryProps.onMuteParticipant
: undefined, localScreenShareView: props.localScreenShareView })));
}, [
videoGalleryProps,
videoTilesOptions,
galleryStyles,
props.isMobile,
props.localVideoTileOptions,
props.userSetGalleryLayout,
cameraSwitcherProps,
onRenderAvatar,
remoteVideoTileMenuOptions,
overflowGalleryPosition,
userRole,
isRoomsCall,
pinnedParticipants,
onPinParticipant,
onUnpinParticipant,
reactionResources,
hideSpotlightButtons,
onStartLocalSpotlightWithPrompt,
onStopLocalSpotlightWithPrompt,
onStartRemoteSpotlightWithPrompt,
onStopRemoteSpotlightWithPrompt,
layoutBasedOnTilePosition,
capabilities === null || capabilities === void 0 ? void 0 : capabilities.muteOthers,
props.localScreenShareView,
compositeContainerAspectRatio
]);
return (React.createElement("div", { ref: containerRef, style: mediaGalleryContainerStyles },
React.createElement(Announcer, { announcementString: announcerString, ariaLive: 'polite' }),
VideoGalleryMemoized));
};
const mediaGalleryContainerStyles = { width: '100%', height: '100%' };
const getVideoGalleryLayoutBasedOnLocalOptions = (localTileOptions) => {
return localTileOptions === 'grid' ? 'default' : 'floatingLocalVideo';
};
//# sourceMappingURL=MediaGallery.js.map