communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
99 lines • 5.94 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import React, { useMemo, useRef, useState } from 'react';
import { isNarrowWidth } from '../utils/responsive';
import { isShortHeight } from '../utils/responsive';
import { OverflowGallery } from './OverflowGallery';
import { GridLayout } from '../GridLayout';
import { Stack } from '@fluentui/react';
import { renderTiles, useOrganizedParticipants } from './utils/videoGalleryLayoutUtils';
import { rootLayoutStyle } from './styles/DefaultLayout.styles';
import { videoGalleryLayoutGap } from './styles/Layout.styles';
import { VERTICAL_GALLERY_TILE_SIZE_REM } from './styles/VideoGalleryResponsiveVerticalGallery.styles';
const DEFAULT_CHILDREN_PER_PAGE = 5;
const REM_TO_PIXEL = 16;
const LARGE_GALLERY_PARTICIPANT_CAP = 48;
/**
* VideoGallery Layout for when user is in a large meeting and wants to see more participants
*
* Caps the number of tiles that a participant can see in the grid to 49, Video and Audio.
*
* @private
*/
export const LargeGalleryLayout = (props) => {
const { remoteParticipants = [], localParticipant, dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, parentWidth, parentHeight, pinnedParticipantUserIds = [], overflowGalleryPosition = 'horizontalBottom', spotlightedParticipantUserIds = [] } = props;
const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;
const isShort = parentHeight ? isShortHeight(parentHeight) : false;
const maxStreamsTrampoline = () => {
return parentWidth && parentHeight
? calculateMaxTilesInLargeGrid(parentWidth, parentHeight)
: maxRemoteVideoStreams;
};
// 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.
// We need to add the local participant to the pinned participant count so we are placing the speakers correctly.
const childrenPerPage = useRef(DEFAULT_CHILDREN_PER_PAGE);
const { gridParticipants, overflowGalleryParticipants } = useOrganizedParticipants({
remoteParticipants,
localParticipant,
dominantSpeakers,
maxGridParticipants: maxStreamsTrampoline(),
isScreenShareActive: !!screenShareComponent,
maxOverflowGalleryDominantSpeakers: screenShareComponent
? childrenPerPage.current - ((pinnedParticipantUserIds.length + 1) % childrenPerPage.current)
: childrenPerPage.current,
pinnedParticipantUserIds,
/* @conditional-compile-remove(large-gallery) */ layout: 'largeGallery',
spotlightedParticipantUserIds
});
/**
* 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([]);
let { gridTiles, overflowGalleryTiles } = renderTiles(gridParticipants, onRenderRemoteParticipant, maxRemoteVideoStreams, indexesToRender, overflowGalleryParticipants, dominantSpeakers);
if (localVideoComponent) {
if (screenShareComponent || spotlightedParticipantUserIds.length > 0) {
overflowGalleryTiles = [localVideoComponent].concat(overflowGalleryTiles);
}
else {
gridTiles = [localVideoComponent].concat(gridTiles);
}
}
const overflowGallery = useMemo(() => {
if (overflowGalleryTiles.length === 0) {
return null;
}
return (React.createElement(OverflowGallery, { isNarrow: isNarrow, isShort: isShort, shouldFloatLocalVideo: false, overflowGalleryElements: overflowGalleryTiles, horizontalGalleryStyles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery, verticalGalleryStyles: styles === null || styles === void 0 ? void 0 : styles.verticalGallery, overflowGalleryPosition: overflowGalleryPosition, onFetchTilesToRender: setIndexesToRender, onChildrenPerPageChange: (n) => {
childrenPerPage.current = n;
}, parentWidth: parentWidth }));
}, [
isNarrow,
isShort,
overflowGalleryTiles,
styles === null || styles === void 0 ? void 0 : styles.horizontalGallery,
overflowGalleryPosition,
setIndexesToRender,
styles === null || styles === void 0 ? void 0 : styles.verticalGallery,
parentWidth
]);
return (React.createElement(Stack, { horizontal: overflowGalleryPosition === 'verticalRight', styles: rootLayoutStyle, 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)));
};
const overflowGalleryTrampoline = (gallery, galleryPosition) => {
return galleryPosition !== 'horizontalTop' ? gallery : React.createElement(React.Fragment, null);
return gallery;
};
const calculateMaxTilesInLargeGrid = (parentWidth, parentHeight) => {
const xAxisTiles = Math.floor(parentWidth / (VERTICAL_GALLERY_TILE_SIZE_REM.width * REM_TO_PIXEL));
const yAxisTiles = Math.floor(parentHeight / (VERTICAL_GALLERY_TILE_SIZE_REM.minHeight * REM_TO_PIXEL));
return xAxisTiles * yAxisTiles < LARGE_GALLERY_PARTICIPANT_CAP
? xAxisTiles * yAxisTiles
: LARGE_GALLERY_PARTICIPANT_CAP;
};
//# sourceMappingURL=LargeGalleryLayout.js.map