UNPKG

@azure/communication-react

Version:

React library for building modern communication user experiences utilizing Azure Communication Services

84 lines 6.47 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { LayerHost, Stack, mergeStyles, useTheme } from '@fluentui/react'; import { isNarrowWidth } from '../utils/responsive'; import { isShortHeight } from '../utils/responsive'; import React, { useMemo, useRef, useState } from 'react'; import { OverflowGallery } from './OverflowGallery'; import { SMALL_FLOATING_MODAL_SIZE_REM, LARGE_FLOATING_MODAL_SIZE_REM, localVideoTileContainerStyle } from './styles/FloatingLocalVideo.styles'; import { VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM, SHORT_VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM } from './styles/FloatingLocalVideo.styles'; import { renderTiles, useOrganizedParticipants } from './utils/videoGalleryLayoutUtils'; import { GridLayout } from '../GridLayout'; import { rootLayoutStyle } from './styles/FloatingLocalVideoLayout.styles'; import { layerHostStyle, innerLayoutStyle } from './styles/FloatingLocalVideoLayout.styles'; import { videoGalleryLayoutGap } from './styles/Layout.styles'; import { useId } from '@fluentui/react-hooks'; /** * Layout for the gallery mode to highlight the current dominant speaker * * @private */ export const SpeakerVideoLayout = (props) => { const { remoteParticipants = [], dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, parentWidth, parentHeight, overflowGalleryPosition = 'horizontalBottom', pinnedParticipantUserIds = [], localVideoTileSize } = props; const theme = useTheme(); const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false; const isShort = parentHeight ? isShortHeight(parentHeight) : false; // This is for tracking the number of children in the first page of overflow gallery. // This number will be used for the maxOverflowGalleryDominantSpeakers when organizing the remote participants. const childrenPerPage = useRef(4); const { gridParticipants, overflowGalleryParticipants } = useOrganizedParticipants({ remoteParticipants, dominantSpeakers, maxGridParticipants: maxRemoteVideoStreams, isScreenShareActive: !!screenShareComponent, maxOverflowGalleryDominantSpeakers: screenShareComponent ? childrenPerPage.current - pinnedParticipantUserIds.length % childrenPerPage.current : childrenPerPage.current, pinnedParticipantUserIds, layout: 'speaker' }); /** * instantiate indexes available to render with indexes available that would be on first page * * For some components which do not strictly follow the order of the array, we might * re-render the initial tiles -> dispose them -> create new tiles, we need to take care of * this case when those components are here */ const [indexesToRender, setIndexesToRender] = useState([]); const { gridTiles, overflowGalleryTiles } = renderTiles(gridParticipants, onRenderRemoteParticipant, maxRemoteVideoStreams, indexesToRender, overflowGalleryParticipants, dominantSpeakers); const shouldFloatLocalVideo = remoteParticipants.length > 0; if (!shouldFloatLocalVideo && localVideoComponent) { gridTiles.push(localVideoComponent); } const layerHostId = useId('layerhost'); const localVideoSizeRem = useMemo(() => { if (isNarrow || localVideoTileSize === '9:16') { return SMALL_FLOATING_MODAL_SIZE_REM; } if ((overflowGalleryTiles.length > 0 || screenShareComponent) && overflowGalleryPosition === 'verticalRight') { return isNarrow ? SMALL_FLOATING_MODAL_SIZE_REM : isShort ? SHORT_VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM : VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM; } if ((overflowGalleryTiles.length > 0 || screenShareComponent) && overflowGalleryPosition === 'horizontalBottom') { return localVideoTileSize === '16:9' || !isNarrow ? LARGE_FLOATING_MODAL_SIZE_REM : SMALL_FLOATING_MODAL_SIZE_REM; } return LARGE_FLOATING_MODAL_SIZE_REM; }, [overflowGalleryTiles.length, isNarrow, screenShareComponent, isShort, overflowGalleryPosition, localVideoTileSize]); const wrappedLocalVideoComponent = localVideoComponent || screenShareComponent && localVideoComponent ? React.createElement(Stack, { className: mergeStyles(localVideoTileContainerStyle(theme, localVideoSizeRem, !!screenShareComponent, overflowGalleryPosition)) }, localVideoComponent) : undefined; const overflowGallery = useMemo(() => { if (overflowGalleryTiles.length === 0 && !screenShareComponent) { return null; } return React.createElement(OverflowGallery, { isShort: isShort, onFetchTilesToRender: setIndexesToRender, isNarrow: isNarrow, shouldFloatLocalVideo: !!localVideoComponent, overflowGalleryElements: overflowGalleryTiles, horizontalGalleryStyles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery, verticalGalleryStyles: styles === null || styles === void 0 ? void 0 : styles.verticalGallery, overflowGalleryPosition: overflowGalleryPosition, onChildrenPerPageChange: (n) => { childrenPerPage.current = n; }, parentWidth: parentWidth }); }, [isNarrow, isShort, screenShareComponent, overflowGalleryTiles, styles === null || styles === void 0 ? void 0 : styles.horizontalGallery, overflowGalleryPosition, setIndexesToRender, styles === null || styles === void 0 ? void 0 : styles.verticalGallery, parentWidth, localVideoComponent]); return React.createElement(Stack, { styles: rootLayoutStyle }, React.createElement(Stack, { horizontal: overflowGalleryPosition === 'verticalRight', styles: innerLayoutStyle, tokens: videoGalleryLayoutGap }, props.overflowGalleryPosition === 'horizontalTop' ? overflowGallery : React.createElement(React.Fragment, null), screenShareComponent ? screenShareComponent : React.createElement(GridLayout, { key: "grid-layout", styles: styles === null || styles === void 0 ? void 0 : styles.gridLayout }, gridTiles), overflowGalleryTrampoline(overflowGallery, props.overflowGalleryPosition)), React.createElement(LayerHost, { id: layerHostId, className: mergeStyles(layerHostStyle) }), wrappedLocalVideoComponent); }; const overflowGalleryTrampoline = (gallery, galleryPosition) => { return galleryPosition !== 'horizontalTop' ? gallery : React.createElement(React.Fragment, null); }; //# sourceMappingURL=SpeakerVideoLayout.js.map