communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
201 lines • 10.3 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { ContextualMenuItemType, merge } from '@fluentui/react';
import { _preventDismissOnEvent as preventDismissOnEvent } from "../../../acs-ui-common/src";
import React from 'react';
import { useLocale } from '../localization';
import { ControlBarButton } from './ControlBarButton';
import { _HighContrastAwareIcon } from './HighContrastAwareIcon';
import { buttonFlyoutItemStyles } from './styles/ControlBar.styles';
const defaultLocalVideoViewOptions = {
scalingMode: 'Crop',
isMirrored: true
};
/**
* Generates default {@link IContextualMenuProps} for buttons that
* show a drop-down to select devices to use.
*
* @internal
*/
export const generateDefaultDeviceMenuProps = (props, strings, primaryActionItem, isSelectCamAllowed = true, isSelectMicAllowed = true) => {
var _a, _b, _c, _d;
const { microphones, speakers, cameras, selectedMicrophone, selectedSpeaker, selectedCamera, onSelectCamera, onSelectMicrophone, onSelectSpeaker } = props;
const defaultMenuProps = {
items: [],
styles: props.styles,
calloutProps: {
styles: {
root: {
// Confine the menu to the parents bounds.
// More info: https://github.com/microsoft/fluentui/issues/18835
// NB: 95% to keep some space for margin, drop shadow etc around the Callout.
maxWidth: '95%'
}
},
preventDismissOnEvent
}
};
const menuItemStyles = merge(buttonFlyoutItemStyles, (_b = (_a = props.styles) === null || _a === void 0 ? void 0 : _a.menuItemStyles) !== null && _b !== void 0 ? _b : {});
if (cameras && selectedCamera && onSelectCamera && isSelectCamAllowed) {
defaultMenuProps.items.push({
key: 'cameras',
itemType: ContextualMenuItemType.Section,
sectionProps: {
title: strings.cameraMenuTitle,
items: [
{
key: 'sectionCamera',
title: strings.cameraMenuTooltip,
subMenuProps: {
calloutProps: {
preventDismissOnEvent
},
items: cameras.map((camera) => ({
key: camera.id,
text: camera.name,
title: camera.name,
iconProps: {
iconName: 'ContextMenuCameraIcon',
styles: { root: { lineHeight: 0 } }
},
itemProps: {
styles: menuItemStyles
},
canCheck: true,
isChecked: camera.id === (selectedCamera === null || selectedCamera === void 0 ? void 0 : selectedCamera.id),
onClick: () => {
if (camera.id !== (selectedCamera === null || selectedCamera === void 0 ? void 0 : selectedCamera.id)) {
onSelectCamera(camera, defaultLocalVideoViewOptions);
}
}
}))
},
text: selectedCamera.name
}
]
}
});
if (primaryActionItem) {
defaultMenuProps.items.push(primaryActionItem);
}
}
if (microphones && selectedMicrophone && onSelectMicrophone && isSelectMicAllowed) {
// Set props as Microphone if speakers can be enumerated else set as Audio Device
const speakersAvailable = speakers && speakers.length > 0;
const key = speakersAvailable ? 'sectionMicrophone' : 'sectionAudioDevice';
const title = speakersAvailable ? strings.microphoneMenuTooltip : strings.audioDeviceMenuTooltip;
const defaultMicrophoneLabelFallback = (_c = strings.defaultMicrophoneLabelFallback) !== null && _c !== void 0 ? _c : 'Default';
// If the default microphone has no name, use the default fallback label. This occurs on Android WebViews.
const selectedMicIsDefault = selectedMicrophone.id === ((_d = microphones[0]) === null || _d === void 0 ? void 0 : _d.id);
const selectedMicrophoneName = selectedMicIsDefault && !selectedMicrophone.name ? defaultMicrophoneLabelFallback : selectedMicrophone.name;
defaultMenuProps.items.push({
key: 'microphones',
itemType: ContextualMenuItemType.Section,
sectionProps: {
title: strings.microphoneMenuTitle,
items: [
{
key: key,
title: title,
subMenuProps: {
calloutProps: {
preventDismissOnEvent
},
items: microphones.map((microphone, i) => {
const microphoneIsDefault = i === 0;
// If the default microphone has no name, use the default fallback label. This occurs on Android WebViews.
const micLabel = microphoneIsDefault && !microphone.name ? defaultMicrophoneLabelFallback : microphone.name;
return {
key: microphone.id,
text: micLabel,
title: micLabel,
itemProps: {
styles: menuItemStyles
},
iconProps: {
iconName: 'ContextMenuMicIcon',
styles: { root: { lineHeight: 0 } }
},
canCheck: true,
isChecked: microphone.id === (selectedMicrophone === null || selectedMicrophone === void 0 ? void 0 : selectedMicrophone.id),
onClick: () => {
if (microphone.id !== (selectedMicrophone === null || selectedMicrophone === void 0 ? void 0 : selectedMicrophone.id)) {
onSelectMicrophone(microphone);
}
}
};
})
},
text: selectedMicrophoneName
}
]
}
});
}
if (speakers && selectedSpeaker && onSelectSpeaker) {
defaultMenuProps.items.push({
key: 'speakers',
itemType: ContextualMenuItemType.Section,
sectionProps: {
title: strings.speakerMenuTitle,
items: [
{
key: 'sectionSpeaker',
subMenuProps: {
calloutProps: {
preventDismissOnEvent
},
items: speakers.map((speaker) => ({
key: speaker.id,
text: speaker.name,
title: speaker.name,
itemProps: {
styles: menuItemStyles
},
iconProps: {
iconName: 'ContextMenuSpeakerIcon',
styles: { root: { lineHeight: 0 } }
},
canCheck: true,
isChecked: speaker.id === (selectedSpeaker === null || selectedSpeaker === void 0 ? void 0 : selectedSpeaker.id),
onClick: () => {
if (speaker.id !== (selectedSpeaker === null || selectedSpeaker === void 0 ? void 0 : selectedSpeaker.id)) {
onSelectSpeaker(speaker);
}
}
}))
},
text: selectedSpeaker.name
}
]
}
});
}
if (microphones && selectedMicrophone && onSelectMicrophone && isSelectMicAllowed && primaryActionItem) {
defaultMenuProps.items.push(primaryActionItem);
}
if (defaultMenuProps.items.length === 0) {
// Avoids creating an empty context menu.
return undefined;
}
return defaultMenuProps;
};
/**
* A button to open a menu that controls device options.
*
* Can be used with {@link ControlBar}.
*
* @public
*/
export const DevicesButton = (props) => {
var _a, _b, _c;
const { onRenderIcon } = props;
const localeStrings = useLocale().strings.devicesButton;
const strings = Object.assign(Object.assign({}, localeStrings), props.strings);
const devicesButtonMenu = (_a = props.menuProps) !== null && _a !== void 0 ? _a : generateDefaultDeviceMenuProps(Object.assign(Object.assign({}, props), { styles: (_b = props.styles) === null || _b === void 0 ? void 0 : _b.menuStyles }), strings);
const onRenderOptionsIcon = () => {
return React.createElement(_HighContrastAwareIcon, { disabled: props.disabled, iconName: "ControlButtonOptions" });
};
return (React.createElement(ControlBarButton, Object.assign({}, props, { menuProps: devicesButtonMenu, menuIconProps: { hidden: true }, onRenderIcon: onRenderIcon !== null && onRenderIcon !== void 0 ? onRenderIcon : onRenderOptionsIcon, strings: strings, labelKey: (_c = props.labelKey) !== null && _c !== void 0 ? _c : 'devicesButtonLabel' })));
};
//# sourceMappingURL=DevicesButton.js.map