@azure/communication-react 1.4.3-alpha-202212130014.0 → 1.4.3-alpha-202212150014.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/dist-cjs/communication-react/index.js +576 -518
  2. package/dist/dist-cjs/communication-react/index.js.map +1 -1
  3. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js +1 -1
  4. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js.map +1 -1
  5. package/dist/dist-esm/calling-component-bindings/src/baseSelectors.d.ts +5 -0
  6. package/dist/dist-esm/calling-component-bindings/src/baseSelectors.js +7 -0
  7. package/dist/dist-esm/calling-component-bindings/src/baseSelectors.js.map +1 -1
  8. package/dist/dist-esm/calling-stateful-client/src/TypeGuards.js +2 -2
  9. package/dist/dist-esm/calling-stateful-client/src/TypeGuards.js.map +1 -1
  10. package/dist/dist-esm/react-components/src/components/UnsupportedEnvironment.js +1 -1
  11. package/dist/dist-esm/react-components/src/components/UnsupportedEnvironment.js.map +1 -1
  12. package/dist/dist-esm/react-components/src/components/styles/UnsupportedEnvironment.styles.js +4 -4
  13. package/dist/dist-esm/react-components/src/components/styles/UnsupportedEnvironment.styles.js.map +1 -1
  14. package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/AzureCommunicationCallAdapter.js +4 -1
  15. package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/AzureCommunicationCallAdapter.js.map +1 -1
  16. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/CallArrangement.js +11 -11
  17. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/CallArrangement.js.map +1 -1
  18. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/buttons/Microphone.js +1 -1
  19. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/buttons/Microphone.js.map +1 -1
  20. package/dist/dist-esm/react-composites/src/composites/CallComposite/hooks/useAdaptedSelector.js +11 -3
  21. package/dist/dist-esm/react-composites/src/composites/CallComposite/hooks/useAdaptedSelector.js.map +1 -1
  22. package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/CallPage.styles.d.ts +4 -0
  23. package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/CallPage.styles.js +8 -0
  24. package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/CallPage.styles.js.map +1 -1
  25. package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.d.ts +9 -0
  26. package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.js +14 -1
  27. package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.js.map +1 -1
  28. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/CallWithChatControlBar.js +11 -1
  29. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/CallWithChatControlBar.js.map +1 -1
  30. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/styles/CallWithChatCompositeStyles.d.ts +2 -0
  31. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/styles/CallWithChatCompositeStyles.js +15 -0
  32. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/styles/CallWithChatCompositeStyles.js.map +1 -1
  33. package/dist/dist-esm/react-composites/src/composites/ChatComposite/adapter/AzureCommunicationChatAdapter.js +4 -0
  34. package/dist/dist-esm/react-composites/src/composites/ChatComposite/adapter/AzureCommunicationChatAdapter.js.map +1 -1
  35. package/package.json +8 -8
@@ -202,7 +202,7 @@ const _toCommunicationIdentifier = (id) => {
202
202
  // Copyright (c) Microsoft Corporation.
203
203
  // Licensed under the MIT license.
204
204
  // GENERATED FILE. DO NOT EDIT MANUALLY.
205
- var telemetryVersion = '1.4.3-alpha-202212130014.0';
205
+ var telemetryVersion = '1.4.3-alpha-202212150014.0';
206
206
 
207
207
  // Copyright (c) Microsoft Corporation.
208
208
  /**
@@ -1799,14 +1799,14 @@ const findOldestCallEnded = (calls) => {
1799
1799
  */
1800
1800
  const _isACSCall = (call) => {
1801
1801
  /* @conditional-compile-remove(teams-identity-support) */
1802
- return call.kind === 'Call';
1802
+ return !call.kind || call.kind === 'Call';
1803
1803
  };
1804
1804
  /**
1805
1805
  * @internal
1806
1806
  */
1807
1807
  const _isACSCallAgent = (callAgent) => {
1808
1808
  /* @conditional-compile-remove(teams-identity-support) */
1809
- return callAgent.kind === 'CallAgent';
1809
+ return !callAgent.kind || callAgent.kind === 'CallAgent';
1810
1810
  };
1811
1811
  /**
1812
1812
  * @internal
@@ -11789,8 +11789,8 @@ const linkTextStyles = {
11789
11789
  */
11790
11790
  const containerStyles$2 = {
11791
11791
  root: {
11792
- padding: '2rem',
11793
- maxWidth: _pxToRem(375)
11792
+ maxWidth: _pxToRem(375),
11793
+ padding: '2rem'
11794
11794
  }
11795
11795
  };
11796
11796
  /**
@@ -11801,8 +11801,8 @@ const continueAnywayButtonStyles = (theme) => {
11801
11801
  root: {
11802
11802
  backgroundColor: '#C4314B',
11803
11803
  borderColor: theme.palette.neutralLight,
11804
- padding: '1rem',
11805
- color: theme.palette.white
11804
+ color: theme.palette.white,
11805
+ padding: '1rem'
11806
11806
  }
11807
11807
  };
11808
11808
  };
@@ -11818,7 +11818,7 @@ const UnsupportedEnvironmentContainer = (props) => {
11818
11818
  React__default['default'].createElement(react.Text, { styles: mainTextStyles }, strings === null || strings === void 0 ? void 0 : strings.primaryText),
11819
11819
  React__default['default'].createElement(react.Text, { styles: secondaryTextStyles }, strings === null || strings === void 0 ? void 0 : strings.secondaryText)),
11820
11820
  onTroubleshootingClick && (React__default['default'].createElement(react.Link, { styles: linkTextStyles, onClick: onTroubleshootingClick, "data-ui-id": "unsupported-environment-link" }, strings === null || strings === void 0 ? void 0 : strings.moreHelpLinkText)),
11821
- onContinueClick && (React__default['default'].createElement(react.DefaultButton, { styles: continueAnywayButtonStyles(theme), onClick: onContinueClick }, strings === null || strings === void 0 ? void 0 : strings.continueAnywayButtonText))));
11821
+ onContinueClick && (React__default['default'].createElement(react.DefaultButton, { "data-ui-id": "allowUnsupportedBrowserButton", styles: continueAnywayButtonStyles(theme), onClick: onContinueClick }, strings === null || strings === void 0 ? void 0 : strings.continueAnywayButtonText))));
11822
11822
  };
11823
11823
  /**
11824
11824
  * UI to display to the user that the environment they are using is not supported by calling application.
@@ -14747,6 +14747,280 @@ const convertObservableFileUploadToFileUploadsUiState = (fileUploads) => {
14747
14747
  }, {});
14748
14748
  };
14749
14749
 
14750
+ // Copyright (c) Microsoft Corporation.
14751
+ // Licensed under the MIT license.
14752
+ /**
14753
+ * Subset of CallCompositePages that represent an end call state.
14754
+ * @private
14755
+ */
14756
+ const END_CALL_PAGES = [
14757
+ 'accessDeniedTeamsMeeting',
14758
+ 'joinCallFailedDueToNoNetwork',
14759
+ 'leftCall',
14760
+ /* @conditional-compile-remove(rooms) */ 'deniedPermissionToRoom',
14761
+ 'removedFromCall',
14762
+ /* @conditional-compile-remove(rooms) */ 'roomNotFound',
14763
+ /* @conditional-compile-remove(unsupported-browser) */ 'unsupportedEnvironment'
14764
+ ];
14765
+
14766
+ // Copyright (c) Microsoft Corporation.
14767
+ const ACCESS_DENIED_TEAMS_MEETING_SUB_CODE = 5854;
14768
+ const REMOTE_PSTN_USER_HUNG_UP = 560000;
14769
+ const REMOVED_FROM_CALL_SUB_CODES = [5000, 5300, REMOTE_PSTN_USER_HUNG_UP];
14770
+ /* @conditional-compile-remove(rooms) */
14771
+ const ROOM_NOT_FOUND_SUB_CODE = 5751;
14772
+ /* @conditional-compile-remove(rooms) */
14773
+ const DENIED_PERMISSION_TO_ROOM_SUB_CODE = 5828;
14774
+ /**
14775
+ * @private
14776
+ */
14777
+ const isCameraOn = (state) => {
14778
+ if (state.call) {
14779
+ const stream = state.call.localVideoStreams.find((stream) => stream.mediaStreamType === 'Video');
14780
+ return !!stream;
14781
+ }
14782
+ else {
14783
+ if (state.devices.selectedCamera) {
14784
+ const previewOn = _isPreviewOn(state.devices);
14785
+ return previewOn;
14786
+ }
14787
+ }
14788
+ return false;
14789
+ };
14790
+ /**
14791
+ * Reduce the set of call controls visible on mobile.
14792
+ * For example do not show screenshare button.
14793
+ *
14794
+ * @private
14795
+ */
14796
+ const reduceCallControlsForMobile = (callControlOptions) => {
14797
+ if (callControlOptions === false) {
14798
+ return false;
14799
+ }
14800
+ // Ensure call controls a valid object.
14801
+ const reduceCallControlOptions = callControlOptions === true ? {} : callControlOptions || {};
14802
+ // Set to compressed mode when composite is optimized for mobile
14803
+ reduceCallControlOptions.displayType = 'compact';
14804
+ // Do not show screen share button when composite is optimized for mobile unless the developer
14805
+ // has explicitly opted in.
14806
+ if (reduceCallControlOptions.screenShareButton !== true) {
14807
+ reduceCallControlOptions.screenShareButton = false;
14808
+ }
14809
+ return reduceCallControlOptions;
14810
+ };
14811
+ var CallEndReasons;
14812
+ (function (CallEndReasons) {
14813
+ CallEndReasons[CallEndReasons["LEFT_CALL"] = 0] = "LEFT_CALL";
14814
+ CallEndReasons[CallEndReasons["ACCESS_DENIED"] = 1] = "ACCESS_DENIED";
14815
+ CallEndReasons[CallEndReasons["REMOVED_FROM_CALL"] = 2] = "REMOVED_FROM_CALL";
14816
+ CallEndReasons[CallEndReasons["ROOM_NOT_FOUND"] = 3] = "ROOM_NOT_FOUND";
14817
+ CallEndReasons[CallEndReasons["DENIED_PERMISSION_TO_ROOM"] = 4] = "DENIED_PERMISSION_TO_ROOM";
14818
+ })(CallEndReasons || (CallEndReasons = {}));
14819
+ const getCallEndReason = (call) => {
14820
+ var _a, _b, _c, _d, _e;
14821
+ const remoteParticipantsEndedArray = Array.from(Object.values(call.remoteParticipantsEnded));
14822
+ /**
14823
+ * Handle the special case in a PSTN call where removing the last user kicks the caller out of the call.
14824
+ * The code and subcode is the same as when a user is removed from a teams interop call.
14825
+ * Hence, we look at the last remote participant removed to determine if the last participant removed was a phone number.
14826
+ * If yes, the caller was kicked out of the call, but we need to show them that they left the call.
14827
+ * Note: This check will only work for 1:1 PSTN Calls. The subcode is different for 1:N PSTN calls, and we do not need to handle that case.
14828
+ */
14829
+ if (remoteParticipantsEndedArray.length === 1 &&
14830
+ communicationCommon.isPhoneNumberIdentifier(remoteParticipantsEndedArray[0].identifier) &&
14831
+ ((_a = call.callEndReason) === null || _a === void 0 ? void 0 : _a.subCode) !== REMOTE_PSTN_USER_HUNG_UP) {
14832
+ return CallEndReasons.LEFT_CALL;
14833
+ }
14834
+ if (((_b = call.callEndReason) === null || _b === void 0 ? void 0 : _b.subCode) && call.callEndReason.subCode === ACCESS_DENIED_TEAMS_MEETING_SUB_CODE) {
14835
+ return CallEndReasons.ACCESS_DENIED;
14836
+ }
14837
+ if (((_c = call.callEndReason) === null || _c === void 0 ? void 0 : _c.subCode) && REMOVED_FROM_CALL_SUB_CODES.includes(call.callEndReason.subCode)) {
14838
+ return CallEndReasons.REMOVED_FROM_CALL;
14839
+ }
14840
+ /* @conditional-compile-remove(rooms) */
14841
+ if (((_d = call.callEndReason) === null || _d === void 0 ? void 0 : _d.subCode) && call.callEndReason.subCode === ROOM_NOT_FOUND_SUB_CODE) {
14842
+ return CallEndReasons.ROOM_NOT_FOUND;
14843
+ }
14844
+ /* @conditional-compile-remove(rooms) */
14845
+ if (((_e = call.callEndReason) === null || _e === void 0 ? void 0 : _e.subCode) && call.callEndReason.subCode === DENIED_PERMISSION_TO_ROOM_SUB_CODE) {
14846
+ return CallEndReasons.DENIED_PERMISSION_TO_ROOM;
14847
+ }
14848
+ if (call.callEndReason) {
14849
+ // No error codes match, assume the user simply left the call regularly
14850
+ return CallEndReasons.LEFT_CALL;
14851
+ }
14852
+ throw new Error('No matching call end reason');
14853
+ };
14854
+ /**
14855
+ * Get the current call composite page based on the current call composite state
14856
+ *
14857
+ * @param Call - The current call state
14858
+ * @param previousCall - The state of the most recent previous call that has ended.
14859
+ *
14860
+ * @remarks - The previousCall state is needed to determine if the call has ended.
14861
+ * When the call ends a new call object is created, and so we must lookback at the
14862
+ * previous call state to understand how the call has ended. If there is no previous
14863
+ * call we know that this is a fresh call and can display the configuration page.
14864
+ *
14865
+ * @private
14866
+ */
14867
+ const getCallCompositePage = (call, previousCall, unsupportedBrowserInfo) => {
14868
+ /* @conditional-compile-remove(unsupported-browser) */
14869
+ if (isUnsupportedEnvironment(unsupportedBrowserInfo.features, unsupportedBrowserInfo.environmentInfo, unsupportedBrowserInfo.unsupportedBrowserVersionOptedIn)) {
14870
+ return 'unsupportedEnvironment';
14871
+ }
14872
+ if (call) {
14873
+ // Must check for ongoing call *before* looking at any previous calls.
14874
+ // If the composite completes one call and joins another, the previous calls
14875
+ // will be populated, but not relevant for determining the page.
14876
+ // `_isInLobbyOrConnecting` needs to be checked first because `_isInCall` also returns true when call is in lobby.
14877
+ if (_isInLobbyOrConnecting(call === null || call === void 0 ? void 0 : call.state)) {
14878
+ return 'lobby';
14879
+ // `LocalHold` needs to be checked before `isInCall` since it is also a state that's considered in call.
14880
+ }
14881
+ else if ((call === null || call === void 0 ? void 0 : call.state) === 'LocalHold') {
14882
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
14883
+ return 'hold';
14884
+ }
14885
+ else if (_isInCall(call === null || call === void 0 ? void 0 : call.state)) {
14886
+ return 'call';
14887
+ }
14888
+ else {
14889
+ // When the call object has been constructed after clicking , but before 'connecting' has been
14890
+ // set on the call object, we continue to show the configuration screen.
14891
+ // The call object does not correctly reflect local device state until `call.state` moves to `connecting`.
14892
+ // Moving to the 'lobby' page too soon leads to components that depend on the `call` object to show incorrect
14893
+ // transitional state.
14894
+ return 'configuration';
14895
+ }
14896
+ }
14897
+ if (previousCall) {
14898
+ const reason = getCallEndReason(previousCall);
14899
+ /* @conditional-compile-remove(rooms) */
14900
+ switch (reason) {
14901
+ case CallEndReasons.ROOM_NOT_FOUND:
14902
+ return 'roomNotFound';
14903
+ case CallEndReasons.DENIED_PERMISSION_TO_ROOM:
14904
+ return 'deniedPermissionToRoom';
14905
+ }
14906
+ switch (reason) {
14907
+ case CallEndReasons.ACCESS_DENIED:
14908
+ return 'accessDeniedTeamsMeeting';
14909
+ case CallEndReasons.REMOVED_FROM_CALL:
14910
+ return 'removedFromCall';
14911
+ case CallEndReasons.LEFT_CALL:
14912
+ if (previousCall.diagnostics.network.latest.noNetwork) {
14913
+ return 'joinCallFailedDueToNoNetwork';
14914
+ }
14915
+ return 'leftCall';
14916
+ }
14917
+ }
14918
+ // No call state - show starting page (configuration)
14919
+ return 'configuration';
14920
+ };
14921
+ /** @private */
14922
+ const IsCallEndedPage = (
14923
+ /**
14924
+ * Explicitly listing the pages of this function intentionally.
14925
+ * This protects against adding a new composite page that should be marked as an callEndedPage.
14926
+ * EndCallPages are used to trigger onCallEnded events so this could easily be missed.
14927
+ * When you add a new composite page this will throw a compiler error. If this new page is an
14928
+ * EndCallPage ensure you update the END_CALL_PAGES. Afterwards update the `page` parameter
14929
+ * type below to allow your new page, i.e. add `| <your new page>
14930
+ */
14931
+ page) => END_CALL_PAGES.includes(page);
14932
+ /**
14933
+ * Creates a new call control options object and sets the correct values for disabling
14934
+ * the buttons provided in the `disabledControls` array.
14935
+ * Returns a new object without changing the original object.
14936
+ * @param callControlOptions options for the call control component that need to be modified.
14937
+ * @param disabledControls An array of controls to disable.
14938
+ * @returns a copy of callControlOptions with disabledControls disabled
14939
+ * @private
14940
+ */
14941
+ const disableCallControls = (callControlOptions, disabledControls) => {
14942
+ var _a;
14943
+ if (callControlOptions === false) {
14944
+ return false;
14945
+ }
14946
+ // Ensure we clone the prop if it is an object to ensure we do not mutate the original prop.
14947
+ let newOptions = (_a = (callControlOptions instanceof Object ? Object.assign({}, callControlOptions) : callControlOptions)) !== null && _a !== void 0 ? _a : {};
14948
+ if (newOptions === true || newOptions === undefined) {
14949
+ newOptions = disabledControls.reduce((acc, key) => {
14950
+ acc[key] = { disabled: true };
14951
+ return acc;
14952
+ }, {});
14953
+ }
14954
+ else {
14955
+ disabledControls.forEach((key) => {
14956
+ if (newOptions[key] !== false) {
14957
+ newOptions[key] = { disabled: true };
14958
+ }
14959
+ });
14960
+ }
14961
+ return newOptions;
14962
+ };
14963
+ /**
14964
+ * Check if a disabled object is provided for a button and returns if the button is disabled.
14965
+ * A button is only disabled if is explicitly set to disabled.
14966
+ *
14967
+ * @param option
14968
+ * @returns whether a button is disabled
14969
+ * @private
14970
+ */
14971
+ const isDisabled$2 = (option) => {
14972
+ if (option === undefined || typeof option === 'boolean') {
14973
+ return false;
14974
+ }
14975
+ return option.disabled;
14976
+ };
14977
+ /* @conditional-compile-remove(call-readiness) */
14978
+ /**
14979
+ *
14980
+ * This function uses permission API to determine if device permission state is granted, prompt or denied
14981
+ * @returns whether device permission state is granted, prompt or denied
14982
+ * If permission API is not supported on this browser, do nothing and log out error
14983
+ * @private
14984
+ */
14985
+ const getDevicePermissionState = (setVideoState, setAudioState) => {
14986
+ navigator.permissions
14987
+ .query({ name: 'camera' })
14988
+ .then((result) => {
14989
+ setVideoState(result.state);
14990
+ })
14991
+ .catch(() => {
14992
+ setVideoState('unsupported');
14993
+ });
14994
+ navigator.permissions
14995
+ .query({ name: 'microphone' })
14996
+ .then((result) => {
14997
+ setAudioState(result.state);
14998
+ })
14999
+ .catch(() => {
15000
+ setAudioState('unsupported');
15001
+ });
15002
+ };
15003
+ /* @conditional-compile-remove(unsupported-browser) */
15004
+ const isUnsupportedEnvironment = (features, environmentInfo, unsupportedBrowserVersionOptedIn) => {
15005
+ return !!((features === null || features === void 0 ? void 0 : features.unsupportedEnvironment) &&
15006
+ ((environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowser) === false ||
15007
+ ((environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowserVersion) === false && !unsupportedBrowserVersionOptedIn) ||
15008
+ (environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedPlatform) === false));
15009
+ };
15010
+ /**
15011
+ * Check if an object is identifier.
15012
+ *
15013
+ * @param identifier
15014
+ * @returns whether an identifier is one of identifier types (for runtime validation)
15015
+ * @private
15016
+ */
15017
+ const isValidIdentifier = (identifier) => {
15018
+ return (communicationCommon.isCommunicationUserIdentifier(identifier) ||
15019
+ communicationCommon.isPhoneNumberIdentifier(identifier) ||
15020
+ communicationCommon.isMicrosoftTeamsUserIdentifier(identifier) ||
15021
+ communicationCommon.isUnknownIdentifier(identifier));
15022
+ };
15023
+
14750
15024
  // Copyright (c) Microsoft Corporation.
14751
15025
  // Licensed under the MIT license.
14752
15026
  var __awaiter$c = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
@@ -15097,6 +15371,9 @@ const convertEventType = (type) => {
15097
15371
  * @public
15098
15372
  */
15099
15373
  const createAzureCommunicationChatAdapter = ({ endpoint: endpointUrl, userId, displayName, credential, threadId }) => __awaiter$c(void 0, void 0, void 0, function* () {
15374
+ if (!isValidIdentifier(userId)) {
15375
+ throw new Error('Provided userId is invalid. Please provide valid identifier object.');
15376
+ }
15100
15377
  const chatClient = createStatefulChatClient({
15101
15378
  userId,
15102
15379
  displayName,
@@ -15759,514 +16036,261 @@ const ChatScreenPeoplePane = (props) => {
15759
16036
  return (React__default['default'].createElement(ParticipantContainer, { participantListProps: participantListProps, title: chatListHeader, onFetchAvatarPersonaData: onFetchAvatarPersonaData, onFetchParticipantMenuItems: onFetchParticipantMenuItems, isMobile: isMobile }));
15760
16037
  };
15761
16038
 
15762
- /**
15763
- * @private
15764
- */
15765
- /**
15766
- * @private
15767
- */
15768
- const getFileUploads = (state) => {
15769
- /* @conditional-compile-remove(file-sharing) */
15770
- return state === null || state === void 0 ? void 0 : state.fileUploads;
15771
- };
15772
-
15773
- // Copyright (c) Microsoft Corporation.
15774
- /**
15775
- * @private
15776
- */
15777
- const fileUploadsSelector = reselect.createSelector([getFileUploads], (fileUploads) => {
15778
- const files = Object.values(fileUploads || {}).map((fileUpload) => (Object.assign(Object.assign({}, fileUpload), { uploadComplete: !!fileUpload.metadata })));
15779
- return { files: files };
15780
- });
15781
-
15782
- // Copyright (c) Microsoft Corporation.
15783
- /**
15784
- * @private
15785
- */
15786
- const useSelector$2 = (selector, selectorProps) => {
15787
- // use selector with no adaptation
15788
- return useSelectorWithAdaptation$1(selector, (state) => state, selectorProps);
15789
- };
15790
-
15791
- // Copyright (c) Microsoft Corporation.
15792
- /**
15793
- * @private
15794
- */
15795
- const FileDownloadErrorBar = (props) => {
15796
- const { fileDownloadErrorMessage, onDismissDownloadErrorMessage } = props;
15797
- const messageBarIconProps = { iconName: 'ProtectedDocument' };
15798
- if (fileDownloadErrorMessage !== '') {
15799
- return (React__default['default'].createElement(react.Stack, { horizontal: true, horizontalAlign: "space-between", verticalAlign: "center" },
15800
- React__default['default'].createElement(react.MessageBar, { messageBarType: react.MessageBarType.warning, onDismiss: () => {
15801
- onDismissDownloadErrorMessage();
15802
- }, messageBarIconProps: messageBarIconProps }, fileDownloadErrorMessage)));
15803
- }
15804
- else {
15805
- return React__default['default'].createElement(React__default['default'].Fragment, null);
15806
- }
15807
- };
15808
-
15809
- // Copyright (c) Microsoft Corporation.
15810
- /**
15811
- * @private
15812
- */
15813
- const ChatScreen = (props) => {
15814
- const { onFetchAvatarPersonaData, onRenderMessage, onRenderTypingIndicator, options, styles, fileSharing, formFactor } = props;
15815
- const defaultNumberOfChatMessagesToReload = 5;
15816
- /* @conditional-compile-remove(file-sharing) */
15817
- const [downloadErrorMessage, setDownloadErrorMessage] = React__default['default'].useState('');
15818
- const adapter = useAdapter$1();
15819
- const theme = useTheme();
15820
- React.useEffect(() => {
15821
- // Initial data should be always fetched by the composite(or external caller) instead of the adapter
15822
- adapter.fetchInitialData();
15823
- }, [adapter]);
15824
- const messageThreadProps = usePropsFor$2(MessageThread);
15825
- const sendBoxProps = usePropsFor$2(SendBox);
15826
- const typingIndicatorProps = usePropsFor$2(TypingIndicator);
15827
- const headerProps = useAdaptedSelector$1(getHeaderProps);
15828
- const errorBarProps = usePropsFor$2(ErrorBar);
15829
- const onRenderAvatarCallback = React.useCallback((userId, defaultOptions) => {
15830
- return (React__default['default'].createElement(AvatarPersona, Object.assign({ userId: userId, hidePersonaDetails: true }, defaultOptions, { dataProvider: onFetchAvatarPersonaData })));
15831
- }, [onFetchAvatarPersonaData]);
15832
- const messageThreadStyles = Object.assign({}, messageThreadChatCompositeStyles(theme.semanticColors.bodyBackground), styles === null || styles === void 0 ? void 0 : styles.messageThread);
15833
- const typingIndicatorStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.typingIndicator);
15834
- const sendBoxStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.sendBox);
15835
- const userId = toFlatCommunicationIdentifier(adapter.getState().userId);
15836
- const fileUploadButtonOnChange = React.useCallback((files) => {
15837
- if (!files) {
15838
- return;
15839
- }
15840
- /* @conditional-compile-remove(file-sharing) */
15841
- const fileUploads = adapter.registerActiveFileUploads(Array.from(files));
15842
- /* @conditional-compile-remove(file-sharing) */
15843
- fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler(userId, fileUploads);
15844
- }, [adapter, fileSharing, userId]);
15845
- /* @conditional-compile-remove(file-sharing) */
15846
- const onRenderFileDownloads = React.useCallback((userId, message) => (React__default['default'].createElement(_FileDownloadCards, { userId: userId, fileMetadata: message.attachedFilesMetadata || [], downloadHandler: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.downloadHandler, onDownloadErrorMessage: (errorMessage) => {
15847
- setDownloadErrorMessage(errorMessage);
15848
- } })), [fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.downloadHandler]);
15849
- const AttachFileButton = React.useCallback(() => {
15850
- if (!(fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler)) {
15851
- return null;
15852
- }
15853
- return (React__default['default'].createElement(FileUploadButtonWrapper, { accept: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.accept, multiple: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.multiple, onChange: fileUploadButtonOnChange }));
15854
- }, [fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.accept, fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.multiple, fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler, fileUploadButtonOnChange]);
15855
- return (React__default['default'].createElement(react.Stack, { className: chatContainer, grow: true },
15856
- (options === null || options === void 0 ? void 0 : options.topic) !== false && React__default['default'].createElement(ChatHeader, Object.assign({}, headerProps)),
15857
- React__default['default'].createElement(react.Stack, { className: chatArea, tokens: participantListContainerPadding, horizontal: true, grow: true },
15858
- React__default['default'].createElement(react.Stack, { className: chatWrapper, grow: true },
15859
- (options === null || options === void 0 ? void 0 : options.errorBar) !== false && React__default['default'].createElement(ErrorBar, Object.assign({}, errorBarProps)),
15860
- /* @conditional-compile-remove(file-sharing) */
15861
- React__default['default'].createElement(FileDownloadErrorBar, { onDismissDownloadErrorMessage: React.useCallback(() => {
15862
- setDownloadErrorMessage('');
15863
- }, []), fileDownloadErrorMessage: downloadErrorMessage || '' }),
15864
- React__default['default'].createElement(MessageThread, Object.assign({}, messageThreadProps, { onRenderAvatar: onRenderAvatarCallback, onRenderMessage: onRenderMessage,
15865
- /* @conditional-compile-remove(file-sharing) */
15866
- onRenderFileDownloads: onRenderFileDownloads, numberOfChatMessagesToReload: defaultNumberOfChatMessagesToReload, styles: messageThreadStyles })),
15867
- React__default['default'].createElement(react.Stack, { className: react.mergeStyles(sendboxContainerStyles) },
15868
- React__default['default'].createElement("div", { className: react.mergeStyles(typingIndicatorContainerStyles) }, onRenderTypingIndicator ? (onRenderTypingIndicator(typingIndicatorProps.typingUsers)) : (React__default['default'].createElement(TypingIndicator, Object.assign({}, typingIndicatorProps, { styles: typingIndicatorStyles })))),
15869
- React__default['default'].createElement(react.Stack, { horizontal: formFactor === 'mobile' },
15870
- formFactor === 'mobile' && (React__default['default'].createElement(react.Stack, { verticalAlign: "center" },
15871
- React__default['default'].createElement(AttachFileButton, null))),
15872
- React__default['default'].createElement(react.Stack, { grow: true },
15873
- React__default['default'].createElement(SendBox, Object.assign({}, sendBoxProps, { autoFocus: options === null || options === void 0 ? void 0 : options.autoFocus, styles: sendBoxStyles,
15874
- /* @conditional-compile-remove(file-sharing) */
15875
- activeFileUploads: useSelector$2(fileUploadsSelector).files,
15876
- /* @conditional-compile-remove(file-sharing) */
15877
- onCancelFileUpload: adapter.cancelFileUpload }))),
15878
- formFactor !== 'mobile' && React__default['default'].createElement(AttachFileButton, null)))),
15879
- /* @conditional-compile-remove(chat-composite-participant-pane) */
15880
- (options === null || options === void 0 ? void 0 : options.participantPane) === true && (React__default['default'].createElement(ChatScreenPeoplePane, { onFetchAvatarPersonaData: onFetchAvatarPersonaData, onFetchParticipantMenuItems: props.onFetchParticipantMenuItems, isMobile: formFactor === 'mobile' })))));
15881
- };
15882
-
15883
- // Copyright (c) Microsoft Corporation.
15884
- /**
15885
- * A customizable UI composite for the chat experience.
15886
- *
15887
- * @remarks Chat composite min width and height are respectively 17.5rem and 20rem (280px and 320px, with default rem at 16px)
15888
- *
15889
- * @public
15890
- */
15891
- const ChatComposite = (props) => {
15892
- const { adapter, options, onFetchAvatarPersonaData, onRenderTypingIndicator, onRenderMessage, onFetchParticipantMenuItems } = props;
15893
- const formFactor = props['formFactor'] || 'desktop';
15894
- /**
15895
- * @TODO Remove this function and pass the props directly when file-sharing is promoted to stable.
15896
- * @private
15897
- */
15898
- // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
15899
- const fileSharingOptions = () => {
15900
- /* @conditional-compile-remove(file-sharing) */
15901
- return {
15902
- fileSharing: options === null || options === void 0 ? void 0 : options.fileSharing
15903
- };
15904
- };
15905
- return (React__default['default'].createElement("div", { className: chatScreenContainerStyle },
15906
- React__default['default'].createElement(BaseProvider, Object.assign({}, props),
15907
- React__default['default'].createElement(ChatAdapterProvider, { adapter: adapter },
15908
- React__default['default'].createElement(ChatScreen, Object.assign({ formFactor: formFactor, options: options, onFetchAvatarPersonaData: onFetchAvatarPersonaData, onRenderTypingIndicator: onRenderTypingIndicator, onRenderMessage: onRenderMessage, onFetchParticipantMenuItems: onFetchParticipantMenuItems }, fileSharingOptions()))))));
15909
- };
15910
-
15911
- // Copyright (c) Microsoft Corporation.
15912
- const CallAdapterContext = React.createContext(undefined);
15913
- /**
15914
- * @private
15915
- */
15916
- const CallAdapterProvider = (props) => {
15917
- const { adapter } = props;
15918
- return React__default['default'].createElement(CallAdapterContext.Provider, { value: adapter }, props.children);
15919
- };
15920
- /**
15921
- * @private
15922
- */
15923
- const useAdapter = () => {
15924
- const adapter = React.useContext(CallAdapterContext);
15925
- if (!adapter) {
15926
- throw 'Cannot find adapter please initialize before usage.';
15927
- }
15928
- return adapter;
15929
- };
15930
-
15931
- // Copyright (c) Microsoft Corporation.
15932
- // Licensed under the MIT license.
15933
- /** @private */
15934
- const containerDivStyles = { position: 'relative', width: '100%', height: '100%' };
15935
-
15936
- // Copyright (c) Microsoft Corporation.
15937
- /**
15938
- * @private
15939
- */
15940
- const useAdaptedSelector = (selector, selectorProps) => {
15941
- return useSelectorWithAdaptation(selector, adaptCompositeState, selectorProps);
15942
- };
15943
- /**
15944
- * @private
15945
- */
15946
- const useSelectorWithAdaptation = (selector, adaptState, selectorProps) => {
15947
- var _a;
15948
- const adapter = useAdapter();
15949
- // Keeps track of whether the current component is mounted or not. If it has unmounted, make sure we do not modify the
15950
- // state or it will cause React warnings in the console. https://skype.visualstudio.com/SPOOL/_workitems/edit/2453212
15951
- const mounted = React.useRef(false);
15952
- React.useEffect(() => {
15953
- mounted.current = true;
15954
- return () => {
15955
- mounted.current = false;
15956
- };
15957
- });
15958
- const callId = (_a = adapter.getState().call) === null || _a === void 0 ? void 0 : _a.id;
15959
- const callConfigProps = React.useMemo(() => ({
15960
- callId
15961
- }), [callId]);
15962
- const [props, setProps] = React.useState(selector(adaptState(adapter.getState()), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps));
15963
- const propRef = React.useRef(props);
15964
- propRef.current = props;
15965
- React.useEffect(() => {
15966
- const onStateChange = (state) => {
15967
- if (!mounted.current) {
15968
- return;
15969
- }
15970
- const newProps = selector(adaptState(state), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps);
15971
- if (propRef.current !== newProps) {
15972
- setProps(newProps);
15973
- }
15974
- };
15975
- adapter.onStateChange(onStateChange);
15976
- return () => {
15977
- adapter.offStateChange(onStateChange);
15978
- };
15979
- }, [adaptState, adapter, selector, selectorProps, callConfigProps]);
15980
- return props;
15981
- };
15982
- const memoizeState = memoizeOne__default['default']((userId, deviceManager, calls, latestErrors, displayName) => ({
15983
- userId,
15984
- incomingCalls: {},
15985
- incomingCallsEnded: {},
15986
- callsEnded: {},
15987
- deviceManager,
15988
- callAgent: { displayName },
15989
- calls,
15990
- latestErrors
15991
- }));
15992
- const memoizeCalls = memoizeOne__default['default']((call) => (call ? { [call.id]: call } : {}));
15993
- const adaptCompositeState = (compositeState) => {
15994
- return memoizeState(compositeState.userId, compositeState.devices, memoizeCalls(compositeState.call),
15995
- // This is an unsafe type expansion.
15996
- // compositeState.latestErrors can contain properties that are not valid in CallErrors.
15997
- //
15998
- // But there is no way to check for valid property names at runtime:
15999
- // - The set of valid property names is built from types in the @azure/communication-calling.
16000
- // Thus we don't have a literal array of allowed strings at runtime.
16001
- // - Due to minification / uglification, the property names from the objects at runtime can't be used
16002
- // to compare against permissible values inferred from the types.
16003
- //
16004
- // This is not a huge problem -- it simply means that our adapted selector will include some extra operations
16005
- // that are unknown to the UI component and data binding libraries. Generic handling of the errors (e.g.,
16006
- // just displaying them in some UI surface) will continue to work for these operations. Handling of
16007
- // specific operations (e.g., acting on errors related to permission issues) will ignore these operations.
16008
- compositeState.latestErrors, compositeState.displayName);
16009
- };
16010
-
16039
+ /**
16040
+ * @private
16041
+ */
16042
+ /**
16043
+ * @private
16044
+ */
16045
+ const getFileUploads = (state) => {
16046
+ /* @conditional-compile-remove(file-sharing) */
16047
+ return state === null || state === void 0 ? void 0 : state.fileUploads;
16048
+ };
16049
+
16011
16050
  // Copyright (c) Microsoft Corporation.
16012
- // Licensed under the MIT license.
16013
16051
  /**
16014
- * Subset of CallCompositePages that represent an end call state.
16015
16052
  * @private
16016
16053
  */
16017
- const END_CALL_PAGES = [
16018
- 'accessDeniedTeamsMeeting',
16019
- 'joinCallFailedDueToNoNetwork',
16020
- 'leftCall',
16021
- /* @conditional-compile-remove(rooms) */ 'deniedPermissionToRoom',
16022
- 'removedFromCall',
16023
- /* @conditional-compile-remove(rooms) */ 'roomNotFound',
16024
- /* @conditional-compile-remove(unsupported-browser) */ 'unsupportedEnvironment'
16025
- ];
16054
+ const fileUploadsSelector = reselect.createSelector([getFileUploads], (fileUploads) => {
16055
+ const files = Object.values(fileUploads || {}).map((fileUpload) => (Object.assign(Object.assign({}, fileUpload), { uploadComplete: !!fileUpload.metadata })));
16056
+ return { files: files };
16057
+ });
16026
16058
 
16027
16059
  // Copyright (c) Microsoft Corporation.
16028
- const ACCESS_DENIED_TEAMS_MEETING_SUB_CODE = 5854;
16029
- const REMOTE_PSTN_USER_HUNG_UP = 560000;
16030
- const REMOVED_FROM_CALL_SUB_CODES = [5000, 5300, REMOTE_PSTN_USER_HUNG_UP];
16031
- /* @conditional-compile-remove(rooms) */
16032
- const ROOM_NOT_FOUND_SUB_CODE = 5751;
16033
- /* @conditional-compile-remove(rooms) */
16034
- const DENIED_PERMISSION_TO_ROOM_SUB_CODE = 5828;
16035
16060
  /**
16036
16061
  * @private
16037
16062
  */
16038
- const isCameraOn = (state) => {
16039
- if (state.call) {
16040
- const stream = state.call.localVideoStreams.find((stream) => stream.mediaStreamType === 'Video');
16041
- return !!stream;
16042
- }
16043
- else {
16044
- if (state.devices.selectedCamera) {
16045
- const previewOn = _isPreviewOn(state.devices);
16046
- return previewOn;
16047
- }
16048
- }
16049
- return false;
16063
+ const useSelector$2 = (selector, selectorProps) => {
16064
+ // use selector with no adaptation
16065
+ return useSelectorWithAdaptation$1(selector, (state) => state, selectorProps);
16050
16066
  };
16067
+
16068
+ // Copyright (c) Microsoft Corporation.
16051
16069
  /**
16052
- * Reduce the set of call controls visible on mobile.
16053
- * For example do not show screenshare button.
16054
- *
16055
16070
  * @private
16056
16071
  */
16057
- const reduceCallControlsForMobile = (callControlOptions) => {
16058
- if (callControlOptions === false) {
16059
- return false;
16060
- }
16061
- // Ensure call controls a valid object.
16062
- const reduceCallControlOptions = callControlOptions === true ? {} : callControlOptions || {};
16063
- // Set to compressed mode when composite is optimized for mobile
16064
- reduceCallControlOptions.displayType = 'compact';
16065
- // Do not show screen share button when composite is optimized for mobile unless the developer
16066
- // has explicitly opted in.
16067
- if (reduceCallControlOptions.screenShareButton !== true) {
16068
- reduceCallControlOptions.screenShareButton = false;
16069
- }
16070
- return reduceCallControlOptions;
16071
- };
16072
- var CallEndReasons;
16073
- (function (CallEndReasons) {
16074
- CallEndReasons[CallEndReasons["LEFT_CALL"] = 0] = "LEFT_CALL";
16075
- CallEndReasons[CallEndReasons["ACCESS_DENIED"] = 1] = "ACCESS_DENIED";
16076
- CallEndReasons[CallEndReasons["REMOVED_FROM_CALL"] = 2] = "REMOVED_FROM_CALL";
16077
- CallEndReasons[CallEndReasons["ROOM_NOT_FOUND"] = 3] = "ROOM_NOT_FOUND";
16078
- CallEndReasons[CallEndReasons["DENIED_PERMISSION_TO_ROOM"] = 4] = "DENIED_PERMISSION_TO_ROOM";
16079
- })(CallEndReasons || (CallEndReasons = {}));
16080
- const getCallEndReason = (call) => {
16081
- var _a, _b, _c, _d, _e;
16082
- const remoteParticipantsEndedArray = Array.from(Object.values(call.remoteParticipantsEnded));
16083
- /**
16084
- * Handle the special case in a PSTN call where removing the last user kicks the caller out of the call.
16085
- * The code and subcode is the same as when a user is removed from a teams interop call.
16086
- * Hence, we look at the last remote participant removed to determine if the last participant removed was a phone number.
16087
- * If yes, the caller was kicked out of the call, but we need to show them that they left the call.
16088
- * Note: This check will only work for 1:1 PSTN Calls. The subcode is different for 1:N PSTN calls, and we do not need to handle that case.
16089
- */
16090
- if (remoteParticipantsEndedArray.length === 1 &&
16091
- communicationCommon.isPhoneNumberIdentifier(remoteParticipantsEndedArray[0].identifier) &&
16092
- ((_a = call.callEndReason) === null || _a === void 0 ? void 0 : _a.subCode) !== REMOTE_PSTN_USER_HUNG_UP) {
16093
- return CallEndReasons.LEFT_CALL;
16094
- }
16095
- if (((_b = call.callEndReason) === null || _b === void 0 ? void 0 : _b.subCode) && call.callEndReason.subCode === ACCESS_DENIED_TEAMS_MEETING_SUB_CODE) {
16096
- return CallEndReasons.ACCESS_DENIED;
16097
- }
16098
- if (((_c = call.callEndReason) === null || _c === void 0 ? void 0 : _c.subCode) && REMOVED_FROM_CALL_SUB_CODES.includes(call.callEndReason.subCode)) {
16099
- return CallEndReasons.REMOVED_FROM_CALL;
16100
- }
16101
- /* @conditional-compile-remove(rooms) */
16102
- if (((_d = call.callEndReason) === null || _d === void 0 ? void 0 : _d.subCode) && call.callEndReason.subCode === ROOM_NOT_FOUND_SUB_CODE) {
16103
- return CallEndReasons.ROOM_NOT_FOUND;
16104
- }
16105
- /* @conditional-compile-remove(rooms) */
16106
- if (((_e = call.callEndReason) === null || _e === void 0 ? void 0 : _e.subCode) && call.callEndReason.subCode === DENIED_PERMISSION_TO_ROOM_SUB_CODE) {
16107
- return CallEndReasons.DENIED_PERMISSION_TO_ROOM;
16072
+ const FileDownloadErrorBar = (props) => {
16073
+ const { fileDownloadErrorMessage, onDismissDownloadErrorMessage } = props;
16074
+ const messageBarIconProps = { iconName: 'ProtectedDocument' };
16075
+ if (fileDownloadErrorMessage !== '') {
16076
+ return (React__default['default'].createElement(react.Stack, { horizontal: true, horizontalAlign: "space-between", verticalAlign: "center" },
16077
+ React__default['default'].createElement(react.MessageBar, { messageBarType: react.MessageBarType.warning, onDismiss: () => {
16078
+ onDismissDownloadErrorMessage();
16079
+ }, messageBarIconProps: messageBarIconProps }, fileDownloadErrorMessage)));
16108
16080
  }
16109
- if (call.callEndReason) {
16110
- // No error codes match, assume the user simply left the call regularly
16111
- return CallEndReasons.LEFT_CALL;
16081
+ else {
16082
+ return React__default['default'].createElement(React__default['default'].Fragment, null);
16112
16083
  }
16113
- throw new Error('No matching call end reason');
16114
16084
  };
16085
+
16086
+ // Copyright (c) Microsoft Corporation.
16115
16087
  /**
16116
- * Get the current call composite page based on the current call composite state
16117
- *
16118
- * @param Call - The current call state
16119
- * @param previousCall - The state of the most recent previous call that has ended.
16120
- *
16121
- * @remarks - The previousCall state is needed to determine if the call has ended.
16122
- * When the call ends a new call object is created, and so we must lookback at the
16123
- * previous call state to understand how the call has ended. If there is no previous
16124
- * call we know that this is a fresh call and can display the configuration page.
16125
- *
16126
16088
  * @private
16127
16089
  */
16128
- const getCallCompositePage = (call, previousCall, unsupportedBrowserInfo) => {
16129
- /* @conditional-compile-remove(unsupported-browser) */
16130
- if (isUnsupportedEnvironment(unsupportedBrowserInfo.features, unsupportedBrowserInfo.environmentInfo, unsupportedBrowserInfo.unsupportedBrowserVersionOptedIn)) {
16131
- return 'unsupportedEnvironment';
16132
- }
16133
- if (call) {
16134
- // Must check for ongoing call *before* looking at any previous calls.
16135
- // If the composite completes one call and joins another, the previous calls
16136
- // will be populated, but not relevant for determining the page.
16137
- // `_isInLobbyOrConnecting` needs to be checked first because `_isInCall` also returns true when call is in lobby.
16138
- if (_isInLobbyOrConnecting(call === null || call === void 0 ? void 0 : call.state)) {
16139
- return 'lobby';
16140
- // `LocalHold` needs to be checked before `isInCall` since it is also a state that's considered in call.
16141
- }
16142
- else if ((call === null || call === void 0 ? void 0 : call.state) === 'LocalHold') {
16143
- /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
16144
- return 'hold';
16145
- }
16146
- else if (_isInCall(call === null || call === void 0 ? void 0 : call.state)) {
16147
- return 'call';
16148
- }
16149
- else {
16150
- // When the call object has been constructed after clicking , but before 'connecting' has been
16151
- // set on the call object, we continue to show the configuration screen.
16152
- // The call object does not correctly reflect local device state until `call.state` moves to `connecting`.
16153
- // Moving to the 'lobby' page too soon leads to components that depend on the `call` object to show incorrect
16154
- // transitional state.
16155
- return 'configuration';
16156
- }
16157
- }
16158
- if (previousCall) {
16159
- const reason = getCallEndReason(previousCall);
16160
- /* @conditional-compile-remove(rooms) */
16161
- switch (reason) {
16162
- case CallEndReasons.ROOM_NOT_FOUND:
16163
- return 'roomNotFound';
16164
- case CallEndReasons.DENIED_PERMISSION_TO_ROOM:
16165
- return 'deniedPermissionToRoom';
16090
+ const ChatScreen = (props) => {
16091
+ const { onFetchAvatarPersonaData, onRenderMessage, onRenderTypingIndicator, options, styles, fileSharing, formFactor } = props;
16092
+ const defaultNumberOfChatMessagesToReload = 5;
16093
+ /* @conditional-compile-remove(file-sharing) */
16094
+ const [downloadErrorMessage, setDownloadErrorMessage] = React__default['default'].useState('');
16095
+ const adapter = useAdapter$1();
16096
+ const theme = useTheme();
16097
+ React.useEffect(() => {
16098
+ // Initial data should be always fetched by the composite(or external caller) instead of the adapter
16099
+ adapter.fetchInitialData();
16100
+ }, [adapter]);
16101
+ const messageThreadProps = usePropsFor$2(MessageThread);
16102
+ const sendBoxProps = usePropsFor$2(SendBox);
16103
+ const typingIndicatorProps = usePropsFor$2(TypingIndicator);
16104
+ const headerProps = useAdaptedSelector$1(getHeaderProps);
16105
+ const errorBarProps = usePropsFor$2(ErrorBar);
16106
+ const onRenderAvatarCallback = React.useCallback((userId, defaultOptions) => {
16107
+ return (React__default['default'].createElement(AvatarPersona, Object.assign({ userId: userId, hidePersonaDetails: true }, defaultOptions, { dataProvider: onFetchAvatarPersonaData })));
16108
+ }, [onFetchAvatarPersonaData]);
16109
+ const messageThreadStyles = Object.assign({}, messageThreadChatCompositeStyles(theme.semanticColors.bodyBackground), styles === null || styles === void 0 ? void 0 : styles.messageThread);
16110
+ const typingIndicatorStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.typingIndicator);
16111
+ const sendBoxStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.sendBox);
16112
+ const userId = toFlatCommunicationIdentifier(adapter.getState().userId);
16113
+ const fileUploadButtonOnChange = React.useCallback((files) => {
16114
+ if (!files) {
16115
+ return;
16166
16116
  }
16167
- switch (reason) {
16168
- case CallEndReasons.ACCESS_DENIED:
16169
- return 'accessDeniedTeamsMeeting';
16170
- case CallEndReasons.REMOVED_FROM_CALL:
16171
- return 'removedFromCall';
16172
- case CallEndReasons.LEFT_CALL:
16173
- if (previousCall.diagnostics.network.latest.noNetwork) {
16174
- return 'joinCallFailedDueToNoNetwork';
16175
- }
16176
- return 'leftCall';
16117
+ /* @conditional-compile-remove(file-sharing) */
16118
+ const fileUploads = adapter.registerActiveFileUploads(Array.from(files));
16119
+ /* @conditional-compile-remove(file-sharing) */
16120
+ fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler(userId, fileUploads);
16121
+ }, [adapter, fileSharing, userId]);
16122
+ /* @conditional-compile-remove(file-sharing) */
16123
+ const onRenderFileDownloads = React.useCallback((userId, message) => (React__default['default'].createElement(_FileDownloadCards, { userId: userId, fileMetadata: message.attachedFilesMetadata || [], downloadHandler: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.downloadHandler, onDownloadErrorMessage: (errorMessage) => {
16124
+ setDownloadErrorMessage(errorMessage);
16125
+ } })), [fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.downloadHandler]);
16126
+ const AttachFileButton = React.useCallback(() => {
16127
+ if (!(fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler)) {
16128
+ return null;
16177
16129
  }
16178
- }
16179
- // No call state - show starting page (configuration)
16180
- return 'configuration';
16130
+ return (React__default['default'].createElement(FileUploadButtonWrapper, { accept: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.accept, multiple: fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.multiple, onChange: fileUploadButtonOnChange }));
16131
+ }, [fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.accept, fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.multiple, fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler, fileUploadButtonOnChange]);
16132
+ return (React__default['default'].createElement(react.Stack, { className: chatContainer, grow: true },
16133
+ (options === null || options === void 0 ? void 0 : options.topic) !== false && React__default['default'].createElement(ChatHeader, Object.assign({}, headerProps)),
16134
+ React__default['default'].createElement(react.Stack, { className: chatArea, tokens: participantListContainerPadding, horizontal: true, grow: true },
16135
+ React__default['default'].createElement(react.Stack, { className: chatWrapper, grow: true },
16136
+ (options === null || options === void 0 ? void 0 : options.errorBar) !== false && React__default['default'].createElement(ErrorBar, Object.assign({}, errorBarProps)),
16137
+ /* @conditional-compile-remove(file-sharing) */
16138
+ React__default['default'].createElement(FileDownloadErrorBar, { onDismissDownloadErrorMessage: React.useCallback(() => {
16139
+ setDownloadErrorMessage('');
16140
+ }, []), fileDownloadErrorMessage: downloadErrorMessage || '' }),
16141
+ React__default['default'].createElement(MessageThread, Object.assign({}, messageThreadProps, { onRenderAvatar: onRenderAvatarCallback, onRenderMessage: onRenderMessage,
16142
+ /* @conditional-compile-remove(file-sharing) */
16143
+ onRenderFileDownloads: onRenderFileDownloads, numberOfChatMessagesToReload: defaultNumberOfChatMessagesToReload, styles: messageThreadStyles })),
16144
+ React__default['default'].createElement(react.Stack, { className: react.mergeStyles(sendboxContainerStyles) },
16145
+ React__default['default'].createElement("div", { className: react.mergeStyles(typingIndicatorContainerStyles) }, onRenderTypingIndicator ? (onRenderTypingIndicator(typingIndicatorProps.typingUsers)) : (React__default['default'].createElement(TypingIndicator, Object.assign({}, typingIndicatorProps, { styles: typingIndicatorStyles })))),
16146
+ React__default['default'].createElement(react.Stack, { horizontal: formFactor === 'mobile' },
16147
+ formFactor === 'mobile' && (React__default['default'].createElement(react.Stack, { verticalAlign: "center" },
16148
+ React__default['default'].createElement(AttachFileButton, null))),
16149
+ React__default['default'].createElement(react.Stack, { grow: true },
16150
+ React__default['default'].createElement(SendBox, Object.assign({}, sendBoxProps, { autoFocus: options === null || options === void 0 ? void 0 : options.autoFocus, styles: sendBoxStyles,
16151
+ /* @conditional-compile-remove(file-sharing) */
16152
+ activeFileUploads: useSelector$2(fileUploadsSelector).files,
16153
+ /* @conditional-compile-remove(file-sharing) */
16154
+ onCancelFileUpload: adapter.cancelFileUpload }))),
16155
+ formFactor !== 'mobile' && React__default['default'].createElement(AttachFileButton, null)))),
16156
+ /* @conditional-compile-remove(chat-composite-participant-pane) */
16157
+ (options === null || options === void 0 ? void 0 : options.participantPane) === true && (React__default['default'].createElement(ChatScreenPeoplePane, { onFetchAvatarPersonaData: onFetchAvatarPersonaData, onFetchParticipantMenuItems: props.onFetchParticipantMenuItems, isMobile: formFactor === 'mobile' })))));
16158
+ };
16159
+
16160
+ // Copyright (c) Microsoft Corporation.
16161
+ /**
16162
+ * A customizable UI composite for the chat experience.
16163
+ *
16164
+ * @remarks Chat composite min width and height are respectively 17.5rem and 20rem (280px and 320px, with default rem at 16px)
16165
+ *
16166
+ * @public
16167
+ */
16168
+ const ChatComposite = (props) => {
16169
+ const { adapter, options, onFetchAvatarPersonaData, onRenderTypingIndicator, onRenderMessage, onFetchParticipantMenuItems } = props;
16170
+ const formFactor = props['formFactor'] || 'desktop';
16171
+ /**
16172
+ * @TODO Remove this function and pass the props directly when file-sharing is promoted to stable.
16173
+ * @private
16174
+ */
16175
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
16176
+ const fileSharingOptions = () => {
16177
+ /* @conditional-compile-remove(file-sharing) */
16178
+ return {
16179
+ fileSharing: options === null || options === void 0 ? void 0 : options.fileSharing
16180
+ };
16181
+ };
16182
+ return (React__default['default'].createElement("div", { className: chatScreenContainerStyle },
16183
+ React__default['default'].createElement(BaseProvider, Object.assign({}, props),
16184
+ React__default['default'].createElement(ChatAdapterProvider, { adapter: adapter },
16185
+ React__default['default'].createElement(ChatScreen, Object.assign({ formFactor: formFactor, options: options, onFetchAvatarPersonaData: onFetchAvatarPersonaData, onRenderTypingIndicator: onRenderTypingIndicator, onRenderMessage: onRenderMessage, onFetchParticipantMenuItems: onFetchParticipantMenuItems }, fileSharingOptions()))))));
16181
16186
  };
16182
- /** @private */
16183
- const IsCallEndedPage = (
16187
+
16188
+ // Copyright (c) Microsoft Corporation.
16189
+ const CallAdapterContext = React.createContext(undefined);
16184
16190
  /**
16185
- * Explicitly listing the pages of this function intentionally.
16186
- * This protects against adding a new composite page that should be marked as an callEndedPage.
16187
- * EndCallPages are used to trigger onCallEnded events so this could easily be missed.
16188
- * When you add a new composite page this will throw a compiler error. If this new page is an
16189
- * EndCallPage ensure you update the END_CALL_PAGES. Afterwards update the `page` parameter
16190
- * type below to allow your new page, i.e. add `| <your new page>
16191
+ * @private
16191
16192
  */
16192
- page) => END_CALL_PAGES.includes(page);
16193
+ const CallAdapterProvider = (props) => {
16194
+ const { adapter } = props;
16195
+ return React__default['default'].createElement(CallAdapterContext.Provider, { value: adapter }, props.children);
16196
+ };
16193
16197
  /**
16194
- * Creates a new call control options object and sets the correct values for disabling
16195
- * the buttons provided in the `disabledControls` array.
16196
- * Returns a new object without changing the original object.
16197
- * @param callControlOptions options for the call control component that need to be modified.
16198
- * @param disabledControls An array of controls to disable.
16199
- * @returns a copy of callControlOptions with disabledControls disabled
16200
16198
  * @private
16201
16199
  */
16202
- const disableCallControls = (callControlOptions, disabledControls) => {
16203
- var _a;
16204
- if (callControlOptions === false) {
16205
- return false;
16206
- }
16207
- // Ensure we clone the prop if it is an object to ensure we do not mutate the original prop.
16208
- let newOptions = (_a = (callControlOptions instanceof Object ? Object.assign({}, callControlOptions) : callControlOptions)) !== null && _a !== void 0 ? _a : {};
16209
- if (newOptions === true || newOptions === undefined) {
16210
- newOptions = disabledControls.reduce((acc, key) => {
16211
- acc[key] = { disabled: true };
16212
- return acc;
16213
- }, {});
16214
- }
16215
- else {
16216
- disabledControls.forEach((key) => {
16217
- if (newOptions[key] !== false) {
16218
- newOptions[key] = { disabled: true };
16219
- }
16220
- });
16200
+ const useAdapter = () => {
16201
+ const adapter = React.useContext(CallAdapterContext);
16202
+ if (!adapter) {
16203
+ throw 'Cannot find adapter please initialize before usage.';
16221
16204
  }
16222
- return newOptions;
16205
+ return adapter;
16223
16206
  };
16207
+
16208
+ // Copyright (c) Microsoft Corporation.
16209
+ // Licensed under the MIT license.
16210
+ /** @private */
16211
+ const containerDivStyles = { position: 'relative', width: '100%', height: '100%' };
16212
+
16213
+ // Copyright (c) Microsoft Corporation.
16224
16214
  /**
16225
- * Check if a disabled object is provided for a button and returns if the button is disabled.
16226
- * A button is only disabled if is explicitly set to disabled.
16227
- *
16228
- * @param option
16229
- * @returns whether a button is disabled
16230
16215
  * @private
16231
16216
  */
16232
- const isDisabled$2 = (option) => {
16233
- if (option === undefined || typeof option === 'boolean') {
16234
- return false;
16235
- }
16236
- return option.disabled;
16217
+ const useAdaptedSelector = (selector, selectorProps) => {
16218
+ return useSelectorWithAdaptation(selector, adaptCompositeState, selectorProps);
16237
16219
  };
16238
- /* @conditional-compile-remove(call-readiness) */
16239
16220
  /**
16240
- *
16241
- * This function uses permission API to determine if device permission state is granted, prompt or denied
16242
- * @returns whether device permission state is granted, prompt or denied
16243
- * If permission API is not supported on this browser, do nothing and log out error
16244
16221
  * @private
16245
16222
  */
16246
- const getDevicePermissionState = (setVideoState, setAudioState) => {
16247
- navigator.permissions
16248
- .query({ name: 'camera' })
16249
- .then((result) => {
16250
- setVideoState(result.state);
16251
- })
16252
- .catch(() => {
16253
- setVideoState('unsupported');
16254
- });
16255
- navigator.permissions
16256
- .query({ name: 'microphone' })
16257
- .then((result) => {
16258
- setAudioState(result.state);
16259
- })
16260
- .catch(() => {
16261
- setAudioState('unsupported');
16223
+ const useSelectorWithAdaptation = (selector, adaptState, selectorProps) => {
16224
+ var _a;
16225
+ const adapter = useAdapter();
16226
+ // Keeps track of whether the current component is mounted or not. If it has unmounted, make sure we do not modify the
16227
+ // state or it will cause React warnings in the console. https://skype.visualstudio.com/SPOOL/_workitems/edit/2453212
16228
+ const mounted = React.useRef(false);
16229
+ React.useEffect(() => {
16230
+ mounted.current = true;
16231
+ return () => {
16232
+ mounted.current = false;
16233
+ };
16262
16234
  });
16235
+ const callId = (_a = adapter.getState().call) === null || _a === void 0 ? void 0 : _a.id;
16236
+ const callConfigProps = React.useMemo(() => ({
16237
+ callId
16238
+ }), [callId]);
16239
+ const [props, setProps] = React.useState(selector(adaptState(adapter.getState()), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps));
16240
+ const propRef = React.useRef(props);
16241
+ propRef.current = props;
16242
+ React.useEffect(() => {
16243
+ const onStateChange = (state) => {
16244
+ if (!mounted.current) {
16245
+ return;
16246
+ }
16247
+ const newProps = selector(adaptState(state), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps);
16248
+ if (propRef.current !== newProps) {
16249
+ setProps(newProps);
16250
+ }
16251
+ };
16252
+ adapter.onStateChange(onStateChange);
16253
+ return () => {
16254
+ adapter.offStateChange(onStateChange);
16255
+ };
16256
+ }, [adaptState, adapter, selector, selectorProps, callConfigProps]);
16257
+ return props;
16263
16258
  };
16264
- /* @conditional-compile-remove(unsupported-browser) */
16265
- const isUnsupportedEnvironment = (features, environmentInfo, unsupportedBrowserVersionOptedIn) => {
16266
- return !!((features === null || features === void 0 ? void 0 : features.unsupportedEnvironment) &&
16267
- ((environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowser) === false ||
16268
- ((environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowserVersion) === false && !unsupportedBrowserVersionOptedIn) ||
16269
- (environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedPlatform) === false));
16259
+ const memoizeState = memoizeOne__default['default']((userId, deviceManager, calls, latestErrors, displayName, alternateCallerId, environmentInfo) => ({
16260
+ userId,
16261
+ incomingCalls: {},
16262
+ incomingCallsEnded: {},
16263
+ callsEnded: {},
16264
+ deviceManager,
16265
+ callAgent: { displayName },
16266
+ calls,
16267
+ latestErrors,
16268
+ /* @conditional-compile-remove(PSTN-calls) */
16269
+ alternateCallerId,
16270
+ /* @conditional-compile-remove(unsupported-browser) */
16271
+ environmentInfo
16272
+ }));
16273
+ const memoizeCalls = memoizeOne__default['default']((call) => (call ? { [call.id]: call } : {}));
16274
+ const adaptCompositeState = (compositeState) => {
16275
+ return memoizeState(compositeState.userId, compositeState.devices, memoizeCalls(compositeState.call),
16276
+ // This is an unsafe type expansion.
16277
+ // compositeState.latestErrors can contain properties that are not valid in CallErrors.
16278
+ //
16279
+ // But there is no way to check for valid property names at runtime:
16280
+ // - The set of valid property names is built from types in the @azure/communication-calling.
16281
+ // Thus we don't have a literal array of allowed strings at runtime.
16282
+ // - Due to minification / uglification, the property names from the objects at runtime can't be used
16283
+ // to compare against permissible values inferred from the types.
16284
+ //
16285
+ // This is not a huge problem -- it simply means that our adapted selector will include some extra operations
16286
+ // that are unknown to the UI component and data binding libraries. Generic handling of the errors (e.g.,
16287
+ // just displaying them in some UI surface) will continue to work for these operations. Handling of
16288
+ // specific operations (e.g., acting on errors related to permission issues) will ignore these operations.
16289
+ compositeState.latestErrors, compositeState.displayName,
16290
+ /* @conditional-compile-remove(PSTN-calls) */
16291
+ compositeState.alternateCallerId,
16292
+ /* @conditional-compile-remove(unsupported-browser) */
16293
+ compositeState.environmentInfo);
16270
16294
  };
16271
16295
 
16272
16296
  // Copyright (c) Microsoft Corporation.
@@ -16665,7 +16689,7 @@ const Microphone = (props) => {
16665
16689
  : {};
16666
16690
  const styles = React.useMemo(() => { var _a; return concatButtonBaseStyles((_a = props.styles) !== null && _a !== void 0 ? _a : {}); }, [props.styles]);
16667
16691
  // tab focus on MicrophoneButton on page load
16668
- return (React__default['default'].createElement(MicrophoneButton, Object.assign({ autoFocus: true, "data-ui-id": "call-composite-microphone-button" }, microphoneButtonProps, { showLabel: props.displayType !== 'compact', styles: styles }, microphoneButtonStrings, { enableDeviceSelectionMenu: props.splitButtonsForDeviceSelection, disabled: microphoneButtonProps.disabled || props.disabled })));
16692
+ return (React__default['default'].createElement(MicrophoneButton, Object.assign({ "data-ui-id": "call-composite-microphone-button" }, microphoneButtonProps, { showLabel: props.displayType !== 'compact', styles: styles }, microphoneButtonStrings, { enableDeviceSelectionMenu: props.splitButtonsForDeviceSelection, disabled: microphoneButtonProps.disabled || props.disabled })));
16669
16693
  };
16670
16694
 
16671
16695
  // Copyright (c) Microsoft Corporation.
@@ -17096,6 +17120,14 @@ const bannerNotificationStyles = {
17096
17120
  pointerEvents: 'auto' // to allow the dismissal or error and warning bars in the notification container
17097
17121
  }
17098
17122
  };
17123
+ /**
17124
+ * @private
17125
+ */
17126
+ const callArrangementContainerStyles = {
17127
+ root: {
17128
+ flexDirection: 'column-reverse' // to allow first initial keyboard focus on ControlBar
17129
+ }
17130
+ };
17099
17131
 
17100
17132
  // Copyright (c) Microsoft Corporation.
17101
17133
  /**
@@ -18081,25 +18113,25 @@ const CallArrangement = (props) => {
18081
18113
  }
18082
18114
  return (React__default['default'].createElement("div", { ref: containerRef, className: react.mergeStyles(containerDivStyles) },
18083
18115
  React__default['default'].createElement(react.Stack, { verticalFill: true, horizontalAlign: "stretch", className: containerClassName, "data-ui-id": props.dataUiId },
18084
- React__default['default'].createElement(react.Stack, { horizontal: true, grow: true },
18116
+ React__default['default'].createElement(react.Stack, { horizontal: true, grow: true, styles: callArrangementContainerStyles },
18085
18117
  React__default['default'].createElement(react.Stack.Item, { styles: notificationsContainerStyles },
18086
18118
  React__default['default'].createElement(react.Stack, { styles: bannerNotificationStyles },
18087
18119
  React__default['default'].createElement(_ComplianceBanner, Object.assign({}, props.complianceBannerProps))),
18088
18120
  errorBarProps !== false && (React__default['default'].createElement(react.Stack, { styles: bannerNotificationStyles },
18089
18121
  React__default['default'].createElement(ErrorBar, Object.assign({}, errorBarProps)))),
18090
18122
  canUnmute && !!props.mutedNotificationProps && React__default['default'].createElement(MutedNotification, Object.assign({}, props.mutedNotificationProps))),
18123
+ ((_b = props.callControlProps) === null || _b === void 0 ? void 0 : _b.options) !== false &&
18124
+ /* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
18125
+ !isMobileWithActivePane && (React__default['default'].createElement(react.Stack.Item, { className: callControlsContainerStyles },
18126
+ React__default['default'].createElement(CallControls, Object.assign({}, props.callControlProps, { containerWidth: containerWidth, containerHeight: containerHeight, isMobile: props.mobileView,
18127
+ /* @conditional-compile-remove(one-to-n-calling) */
18128
+ peopleButtonChecked: activePane === 'people',
18129
+ /* @conditional-compile-remove(one-to-n-calling) */
18130
+ onPeopleButtonClicked: togglePeoplePane })))),
18091
18131
  React__default['default'].createElement(react.Stack.Item, { grow: true, style: callCompositeContainerFlex() },
18092
18132
  React__default['default'].createElement(react.Stack.Item, { styles: callGalleryStyles, grow: true }, props.onRenderGalleryContent && (React__default['default'].createElement(react.Stack, { verticalFill: true, styles: mediaGalleryContainerStyles }, props.onRenderGalleryContent())))),
18093
18133
  /* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
18094
- callPaneContent()),
18095
- ((_b = props.callControlProps) === null || _b === void 0 ? void 0 : _b.options) !== false &&
18096
- /* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
18097
- !isMobileWithActivePane && (React__default['default'].createElement(react.Stack.Item, { className: callControlsContainerStyles },
18098
- React__default['default'].createElement(CallControls, Object.assign({}, props.callControlProps, { containerWidth: containerWidth, containerHeight: containerHeight, isMobile: props.mobileView,
18099
- /* @conditional-compile-remove(one-to-n-calling) */
18100
- peopleButtonChecked: activePane === 'people',
18101
- /* @conditional-compile-remove(one-to-n-calling) */
18102
- onPeopleButtonClicked: togglePeoplePane })))))));
18134
+ callPaneContent()))));
18103
18135
  };
18104
18136
  /* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
18105
18137
  const showShowPeopleTabHeaderButton$1 = (callControls) => {
@@ -20595,6 +20627,9 @@ class AzureCommunicationCallAdapter {
20595
20627
  const createAzureCommunicationCallAdapter = ({ userId, displayName, credential, locator,
20596
20628
  /* @conditional-compile-remove(PSTN-calls) */ alternateCallerId,
20597
20629
  /* @conditional-compile-remove(rooms) */ options }) => __awaiter$4(void 0, void 0, void 0, function* () {
20630
+ if (!isValidIdentifier(userId)) {
20631
+ throw new Error('Invalid identifier. Please provide valid identifier object.');
20632
+ }
20598
20633
  const callClient = createStatefulCallClient({
20599
20634
  userId,
20600
20635
  /* @conditional-compile-remove(PSTN-calls) */ alternateCallerId
@@ -21087,6 +21122,50 @@ const DesktopMoreButton = (props) => {
21087
21122
  strings: moreButtonStrings, menuIconProps: { hidden: true }, menuProps: { items: moreButtonContextualMenuItems() } })));
21088
21123
  };
21089
21124
 
21125
+ // Copyright (c) Microsoft Corporation.
21126
+ // Licensed under the MIT license.
21127
+ /**
21128
+ * @private
21129
+ */
21130
+ const compositeOuterContainerStyles = {
21131
+ root: {
21132
+ width: '100%',
21133
+ // Create a new stacking context so that DrawerMenu can be positioned absolutely.
21134
+ position: 'relative'
21135
+ }
21136
+ };
21137
+ /** @private */
21138
+ const callCompositeContainerStyles = {
21139
+ root: {
21140
+ // Start a new stacking context so that any `position:absolute` elements
21141
+ // inside the call composite do not compete with its siblings.
21142
+ position: 'relative'
21143
+ }
21144
+ };
21145
+ /** @private */
21146
+ const controlBarContainerStyles = {
21147
+ root: {
21148
+ // Start a new stacking context so that any `position:absolute` elements
21149
+ // inside the control bar do not compete with its siblings.
21150
+ position: 'relative'
21151
+ }
21152
+ };
21153
+ /** @private */
21154
+ const hiddenAutoFocusButtonStyles = {
21155
+ root: {
21156
+ width: '0',
21157
+ height: '0',
21158
+ margin: '0',
21159
+ minHeight: '0',
21160
+ minWidth: '0',
21161
+ maxHeight: '0',
21162
+ maxWidth: '0',
21163
+ outline: 'none',
21164
+ padding: '0',
21165
+ position: 'absolute'
21166
+ }
21167
+ };
21168
+
21090
21169
  // Copyright (c) Microsoft Corporation.
21091
21170
  const inferCallWithChatControlOptions$1 = (mobileView, callWithChatControls) => {
21092
21171
  if (callWithChatControls === false) {
@@ -21109,6 +21188,13 @@ const inferCallWithChatControlOptions$1 = (mobileView, callWithChatControls) =>
21109
21188
  */
21110
21189
  const CallWithChatControlBar = (props) => {
21111
21190
  var _a, _b;
21191
+ React.useEffect(() => {
21192
+ var _a;
21193
+ // On mount, button used for initial focus is hidden to prevent screen readers from announcing the initial focus
21194
+ if (document.querySelector('[data-ui-id=call-with-chat-autofocus-hidden-button]') === document.activeElement) {
21195
+ (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.setAttribute('hidden', 'true');
21196
+ }
21197
+ }, []);
21112
21198
  const theme = react.useTheme();
21113
21199
  const callWithChatStrings = useCallWithChatCompositeStrings();
21114
21200
  const options = inferCallWithChatControlOptions$1(props.mobileView, props.callControls);
@@ -21149,6 +21235,7 @@ const CallWithChatControlBar = (props) => {
21149
21235
  React__default['default'].createElement(react.Stack.Item, { grow: true },
21150
21236
  React__default['default'].createElement(CallAdapterProvider, { adapter: props.callAdapter },
21151
21237
  React__default['default'].createElement(react.Stack, { horizontalAlign: "center" },
21238
+ React__default['default'].createElement(ControlBarButton, { autoFocus: true, ariaHidden: true, "data-ui-id": 'call-with-chat-autofocus-hidden-button', styles: hiddenAutoFocusButtonStyles, tabIndex: -1 }),
21152
21239
  React__default['default'].createElement(react.Stack.Item, null,
21153
21240
  React__default['default'].createElement(ControlBar, { layout: "horizontal", styles: centerContainerStyles },
21154
21241
  isEnabled$1(options.microphoneButton) && (React__default['default'].createElement(Microphone, { displayType: options.displayType, styles: commonButtonStyles, splitButtonsForDeviceSelection: !props.mobileView,
@@ -21255,35 +21342,6 @@ const getDesktopEndCallButtonStyles = (theme) => {
21255
21342
  };
21256
21343
  const isEnabled$1 = (option) => option !== false;
21257
21344
 
21258
- // Copyright (c) Microsoft Corporation.
21259
- // Licensed under the MIT license.
21260
- /**
21261
- * @private
21262
- */
21263
- const compositeOuterContainerStyles = {
21264
- root: {
21265
- width: '100%',
21266
- // Create a new stacking context so that DrawerMenu can be positioned absolutely.
21267
- position: 'relative'
21268
- }
21269
- };
21270
- /** @private */
21271
- const callCompositeContainerStyles = {
21272
- root: {
21273
- // Start a new stacking context so that any `position:absolute` elements
21274
- // inside the call composite do not compete with its siblings.
21275
- position: 'relative'
21276
- }
21277
- };
21278
- /** @private */
21279
- const controlBarContainerStyles = {
21280
- root: {
21281
- // Start a new stacking context so that any `position:absolute` elements
21282
- // inside the control bar do not compete with its siblings.
21283
- position: 'relative'
21284
- }
21285
- };
21286
-
21287
21345
  // Copyright (c) Microsoft Corporation.
21288
21346
  // Licensed under the MIT license.
21289
21347
  var __awaiter$3 = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {