communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
114 lines • 7.14 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { DefaultButton, Icon, mergeStyles, Stack, Text } from '@fluentui/react';
import React, { useEffect, useMemo, useState } from 'react';
import { useLocale } from '../localization';
import { useIdentifiers } from '../identifiers';
import { useTheme } from '../theming';
import { childrenContainerStyle, pageNavigationControlBarContainerStyle, participantPageCounter, leftRightButtonStyles, navIconStyles, rootStyle } from './styles/VerticalGallery.styles';
import { bucketize } from './utils/overFlowGalleriesUtils';
import { _formatString } from "../../../acs-ui-common/src";
/**
* VerticalGallery is a overflow gallery for participants in the {@link VideoGallery} component. Stacks
* participants on the Y-axis of the VideoGallery for better use of horizontal space.
*
* @public
*/
export const VerticalGallery = (props) => {
const { children, styles, childrenPerPage, onFetchTilesToRender } = props;
const [page, setPage] = useState(1);
const [buttonState, setButtonState] = useState({ previous: true, next: true });
const ids = useIdentifiers();
const numberOfChildren = React.Children.count(children);
const lastPage = Math.ceil(numberOfChildren / childrenPerPage);
const indexesArray = useMemo(() => {
return bucketize([...Array(numberOfChildren).keys()], childrenPerPage);
}, [numberOfChildren, childrenPerPage]);
useEffect(() => {
var _a;
if (onFetchTilesToRender && indexesArray) {
onFetchTilesToRender((_a = indexesArray[page - 1]) !== null && _a !== void 0 ? _a : []);
}
}, [indexesArray, onFetchTilesToRender, page]);
const firstIndexOfCurrentPage = (page - 1) * childrenPerPage;
const clippedPage = firstIndexOfCurrentPage < numberOfChildren - 1 ? page : lastPage;
const childrenOnCurrentPage = useMemo(() => {
var _a;
if (indexesArray[0] !== undefined) {
return (_a = indexesArray[clippedPage - 1]) === null || _a === void 0 ? void 0 : _a.map((index) => {
return React.Children.toArray(children)[index];
});
}
return;
}, [indexesArray, clippedPage, children]);
const showButtons = numberOfChildren > childrenPerPage;
const onPreviousButtonClick = () => {
setPage(page - 1);
};
const onNextButtonClick = () => {
setPage(page + 1);
};
if (page > lastPage && lastPage > 0) {
setPage(lastPage);
}
useEffect(() => {
if (page > 1 && page < lastPage && showButtons) {
// we are somewhere in between first and last pages.
setButtonState({ previous: false, next: false });
}
else if (page === 1 && showButtons) {
// we are on the first page.
setButtonState({ previous: true, next: false });
}
else if (page === lastPage && showButtons) {
// we are on the last page.
setButtonState({ previous: false, next: true });
}
}, [page, numberOfChildren, lastPage, showButtons]);
const childContainerStyle = useMemo(() => {
return { root: childrenContainerStyle(2) };
}, []);
const childrenStyles = useMemo(() => {
return { root: styles === null || styles === void 0 ? void 0 : styles.children };
}, [styles === null || styles === void 0 ? void 0 : styles.children]);
if (childrenPerPage <= 0) {
return React.createElement(React.Fragment, null);
}
return (React.createElement(Stack, { className: mergeStyles(rootStyle, styles === null || styles === void 0 ? void 0 : styles.root) },
React.createElement(Stack, { styles: childContainerStyle }, childrenOnCurrentPage === null || childrenOnCurrentPage === void 0 ? void 0 : childrenOnCurrentPage.map((child, i) => {
return (React.createElement(Stack.Item, { key: i, styles: childrenStyles, "data-ui-id": ids.verticalGalleryVideoTile }, child));
})),
showButtons && (React.createElement(VerticalGalleryControlBar, { buttonsDisabled: buttonState, onPreviousButtonClick: onPreviousButtonClick, onNextButtonClick: onNextButtonClick, totalPages: lastPage, currentPage: page }))));
};
const VerticalGalleryControlBar = (props) => {
const { onNextButtonClick, onPreviousButtonClick, buttonsDisabled, currentPage, totalPages, styles } = props;
const theme = useTheme();
const ids = useIdentifiers();
const strings = useLocale().strings.verticalGallery;
const pageCounterContainerStyles = useMemo(() => {
return mergeStyles(pageNavigationControlBarContainerStyle, styles === null || styles === void 0 ? void 0 : styles.root);
}, [styles === null || styles === void 0 ? void 0 : styles.root]);
const previousButtonSyles = useMemo(() => {
return mergeStyles(leftRightButtonStyles(theme), styles === null || styles === void 0 ? void 0 : styles.previousButton);
}, [styles === null || styles === void 0 ? void 0 : styles.previousButton, theme]);
const pageCounterStyles = useMemo(() => {
return mergeStyles(participantPageCounter, styles === null || styles === void 0 ? void 0 : styles.counter);
}, [styles === null || styles === void 0 ? void 0 : styles.counter]);
const nextButtonsStyles = useMemo(() => {
return mergeStyles(leftRightButtonStyles(theme), styles === null || styles === void 0 ? void 0 : styles.nextButton);
}, [styles === null || styles === void 0 ? void 0 : styles.nextButton, theme]);
const controlBarSpacing = { childrenGap: '0.5rem' };
const previousButtonAriaLabel = strings.leftNavButtonAriaLabel
? _formatString(strings.leftNavButtonAriaLabel, { current: `${currentPage}`, total: `${totalPages}` })
: undefined;
const nextButtonAriaLabel = strings.rightNavButtonAriaLabel
? _formatString(strings.rightNavButtonAriaLabel, { current: `${currentPage}`, total: `${totalPages}` })
: undefined;
return (React.createElement(Stack, { horizontalAlign: "center", tokens: controlBarSpacing, horizontal: true, className: pageCounterContainerStyles },
React.createElement(DefaultButton, { className: previousButtonSyles, onClick: onPreviousButtonClick, disabled: buttonsDisabled === null || buttonsDisabled === void 0 ? void 0 : buttonsDisabled.previous, ariaLabel: previousButtonAriaLabel, "data-ui-id": ids.overflowGalleryLeftNavButton },
React.createElement(Icon, { iconName: "VerticalGalleryLeftButton", styles: navIconStyles })),
React.createElement(Text, { "data-ui-id": ids.verticalGalleryPageCounter, className: pageCounterStyles }, `${currentPage} / ${totalPages}`),
React.createElement(DefaultButton, { className: nextButtonsStyles, onClick: onNextButtonClick, disabled: buttonsDisabled === null || buttonsDisabled === void 0 ? void 0 : buttonsDisabled.next, ariaLabel: nextButtonAriaLabel, "data-ui-id": ids.overflowGalleryRightNavButton },
React.createElement(Icon, { iconName: "VerticalGalleryRightButton", styles: navIconStyles }))));
};
//# sourceMappingURL=VerticalGallery.js.map