UNPKG

communication-react-19

Version:

React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)

179 lines 9.22 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { ContextualMenuItemType, merge } from '@fluentui/react'; import { _formatString } from "../../../acs-ui-common/src"; import copy from 'copy-to-clipboard'; import React, { useCallback, useMemo, useState } from 'react'; import { ParticipantList } from './ParticipantList'; import { participantsButtonMenuPropsStyle } from './styles/ControlBar.styles'; import { useLocale } from '../localization'; import { ControlBarButton } from './ControlBarButton'; import { useIdentifiers } from '../identifiers'; import { _HighContrastAwareIcon } from './HighContrastAwareIcon'; import { _preventDismissOnEvent as preventDismissOnEvent } from "../../../acs-ui-common/src"; import { Announcer } from './Announcer'; /** * A button to show a menu with calling or chat participants. * * Can be used with {@link ControlBar}. * * This button contains dropdown menu items defined through its property `menuProps`. By default, it can display the number of remote participants with the full list * as sub-menu and an option to mute all participants, as well as a copy-to-clipboard button to copy the call invitation URL. * This `menuProps` can be fully redefined and its property is of type [IContextualMenuProps](https://developer.microsoft.com/fluentui#/controls/web/contextualmenu#IContextualMenuProps). * * @public */ export const ParticipantsButton = (props) => { var _a, _b, _c, _d; const { callInvitationURL, styles, onMuteAll, onRenderIcon, onRenderParticipantList, participants, myUserId, excludeMe, onRenderParticipant, onRenderAvatar, onRemoveParticipant, onFetchParticipantMenuItems, showParticipantOverflowTooltip } = props; const disabled = props.disabled; const [copyInviteLinkAnnouncerStrings, setCopyInviteLinkAnnouncerStrings] = useState(''); const onRenderPeopleIcon = () => (React.createElement(_HighContrastAwareIcon, { disabled: disabled, iconName: "ControlButtonParticipants" })); const ids = useIdentifiers(); const onMuteAllCallback = useCallback(() => { if (onMuteAll) { onMuteAll(); } }, [onMuteAll]); const defaultParticipantList = useCallback(() => { var _a; return (React.createElement(ParticipantList, { participants: participants, myUserId: myUserId, excludeMe: excludeMe, onRenderParticipant: onRenderParticipant, onRenderAvatar: onRenderAvatar, onRemoveParticipant: onRemoveParticipant, onFetchParticipantMenuItems: onFetchParticipantMenuItems, styles: (_a = styles === null || styles === void 0 ? void 0 : styles.menuStyles) === null || _a === void 0 ? void 0 : _a.participantListStyles, showParticipantOverflowTooltip: showParticipantOverflowTooltip })); }, [ excludeMe, myUserId, onRemoveParticipant, onRenderAvatar, onRenderParticipant, participants, (_a = styles === null || styles === void 0 ? void 0 : styles.menuStyles) === null || _a === void 0 ? void 0 : _a.participantListStyles, onFetchParticipantMenuItems, showParticipantOverflowTooltip ]); const onCopyCallback = useCallback(() => { if (callInvitationURL) { return copy(callInvitationURL); } return false; }, [callInvitationURL]); const localeStrings = useLocale().strings.participantsButton; const strings = useMemo(() => (Object.assign(Object.assign({}, localeStrings), props.strings)), [localeStrings, props.strings]); const participantCount = participants.length; /** * sets the announcement string for when the link is copied. */ const toggleAnnouncerString = useCallback(() => { setCopyInviteLinkAnnouncerStrings(strings.copyInviteLinkActionedAriaLabel); /** * Clears the announcer string after the user clicks the * copyInviteLink button allowing it to be re-announced. */ setTimeout(() => { setCopyInviteLinkAnnouncerStrings(''); }, 3000); }, [strings.copyInviteLinkActionedAriaLabel]); const generateDefaultParticipantsSubMenuProps = useCallback(() => { var _a; const items = []; if (participantCount > 0) { items.push({ key: 'participantListMenuItemKey', onRender: onRenderParticipantList !== null && onRenderParticipantList !== void 0 ? onRenderParticipantList : defaultParticipantList }); items.push({ key: 'participantsDivider1', itemType: ContextualMenuItemType.Divider }); if (onMuteAll) { items.push({ key: 'muteAllKey', text: strings.muteAllButtonLabel, title: strings.muteAllButtonLabel, styles: (_a = styles === null || styles === void 0 ? void 0 : styles.menuStyles) === null || _a === void 0 ? void 0 : _a.menuItemStyles, iconProps: { iconName: 'MicOff2' }, onClick: onMuteAllCallback }); } } return items; }, [ participantCount, onRenderParticipantList, defaultParticipantList, onMuteAll, strings.muteAllButtonLabel, (_b = styles === null || styles === void 0 ? void 0 : styles.menuStyles) === null || _b === void 0 ? void 0 : _b.menuItemStyles, onMuteAllCallback ]); const defaultMenuProps = useMemo(() => { var _a, _b; const menuProps = { title: strings.menuHeader, ariaLabel: strings.menuHeader, styles: merge(participantsButtonMenuPropsStyle, styles === null || styles === void 0 ? void 0 : styles.menuStyles), items: [], calloutProps: { preventDismissOnEvent } }; if (participantCount > 0) { const participantIds = participants.map((p) => p.userId); let participantCountWithoutMe = participantIds.length; if (excludeMe) { participantCountWithoutMe -= 1; } menuProps.items.push({ key: 'participantCountKey', name: _formatString(strings.participantsListButtonLabel, { numParticipants: `${participantCountWithoutMe}` }), itemProps: { styles: (_a = styles === null || styles === void 0 ? void 0 : styles.menuStyles) === null || _a === void 0 ? void 0 : _a.menuItemStyles }, iconProps: { iconName: 'People' }, subMenuProps: { items: generateDefaultParticipantsSubMenuProps(), calloutProps: { styles: { root: { // Confine the menu to the parents bounds. // More info: https://github.com/microsoft/fluentui/issues/18835 maxWidth: '100%' } }, style: { maxHeight: '20rem' }, // Disable dismiss on resize to work around a couple Fluent UI bugs // See reasoning in the props for the parent menu. preventDismissOnEvent } }, 'data-ui-id': ids.participantButtonPeopleMenuItem }); } if (callInvitationURL) { menuProps.items.push({ key: 'InviteLinkKey', name: strings.copyInviteLinkButtonLabel, title: strings.copyInviteLinkButtonLabel, itemProps: { styles: (_b = styles === null || styles === void 0 ? void 0 : styles.menuStyles) === null || _b === void 0 ? void 0 : _b.menuItemStyles }, iconProps: { iconName: 'Link' }, onClick: () => { onCopyCallback(); toggleAnnouncerString(); } }); } return menuProps; }, [ strings.menuHeader, strings.participantsListButtonLabel, strings.copyInviteLinkButtonLabel, styles === null || styles === void 0 ? void 0 : styles.menuStyles, participantCount, callInvitationURL, participants, excludeMe, ids.participantButtonPeopleMenuItem, generateDefaultParticipantsSubMenuProps, onCopyCallback, toggleAnnouncerString ]); return (React.createElement(React.Fragment, null, React.createElement(Announcer, { announcementString: copyInviteLinkAnnouncerStrings, ariaLive: 'polite' }), React.createElement(ControlBarButton, Object.assign({}, props, { disabled: disabled, menuProps: (_c = props.menuProps) !== null && _c !== void 0 ? _c : defaultMenuProps, menuIconProps: { hidden: true }, onRenderIcon: onRenderIcon !== null && onRenderIcon !== void 0 ? onRenderIcon : onRenderPeopleIcon, strings: strings, "aria-label": strings.ariaLabel, labelKey: (_d = props.labelKey) !== null && _d !== void 0 ? _d : 'participantsButtonLabel' })))); }; //# sourceMappingURL=ParticipantsButton.js.map