@azure/communication-react 1.5.1-alpha-202306180015 → 1.5.1-alpha-202306210014

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 (65) hide show
  1. package/README.md +2 -3
  2. package/dist/communication-react.d.ts +4 -0
  3. package/dist/dist-cjs/communication-react/index.js +833 -767
  4. package/dist/dist-cjs/communication-react/index.js.map +1 -1
  5. package/dist/dist-esm/acs-ui-common/src/identifier.d.ts +6 -0
  6. package/dist/dist-esm/acs-ui-common/src/identifier.js +12 -1
  7. package/dist/dist-esm/acs-ui-common/src/identifier.js.map +1 -1
  8. package/dist/dist-esm/acs-ui-common/src/index.d.ts +1 -1
  9. package/dist/dist-esm/acs-ui-common/src/index.js +1 -1
  10. package/dist/dist-esm/acs-ui-common/src/index.js.map +1 -1
  11. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js +1 -1
  12. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js.map +1 -1
  13. package/dist/dist-esm/react-components/src/components/HorizontalGallery.js +6 -3
  14. package/dist/dist-esm/react-components/src/components/HorizontalGallery.js.map +1 -1
  15. package/dist/dist-esm/react-components/src/components/InputBoxComponent.js +6 -1
  16. package/dist/dist-esm/react-components/src/components/InputBoxComponent.js.map +1 -1
  17. package/dist/dist-esm/react-components/src/components/ResponsiveVerticalGallery.d.ts +2 -2
  18. package/dist/dist-esm/react-components/src/components/ResponsiveVerticalGallery.js +2 -1
  19. package/dist/dist-esm/react-components/src/components/ResponsiveVerticalGallery.js.map +1 -1
  20. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/TextFieldWithMention.js +25 -39
  21. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/TextFieldWithMention.js.map +1 -1
  22. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/mentionTagUtils.d.ts +0 -1
  23. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/mentionTagUtils.js +50 -21
  24. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/mentionTagUtils.js.map +1 -1
  25. package/dist/dist-esm/react-components/src/components/VerticalGallery.js +6 -3
  26. package/dist/dist-esm/react-components/src/components/VerticalGallery.js.map +1 -1
  27. package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.js +4 -2
  28. package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.js.map +1 -1
  29. package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.js +11 -6
  30. package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.js.map +1 -1
  31. package/dist/dist-esm/react-components/src/components/VideoGallery/Layout.d.ts +3 -1
  32. package/dist/dist-esm/react-components/src/components/VideoGallery/Layout.js.map +1 -1
  33. package/dist/dist-esm/react-components/src/components/VideoGallery/OverflowGallery.js +3 -3
  34. package/dist/dist-esm/react-components/src/components/VideoGallery/OverflowGallery.js.map +1 -1
  35. package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideo.styles.d.ts +1 -1
  36. package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideo.styles.js +6 -3
  37. package/dist/dist-esm/react-components/src/components/VideoGallery/styles/FloatingLocalVideo.styles.js.map +1 -1
  38. package/dist/dist-esm/react-components/src/components/VideoGallery/utils/videoGalleryLayoutUtils.d.ts +1 -0
  39. package/dist/dist-esm/react-components/src/components/VideoGallery/utils/videoGalleryLayoutUtils.js +11 -3
  40. package/dist/dist-esm/react-components/src/components/VideoGallery/utils/videoGalleryLayoutUtils.js.map +1 -1
  41. package/dist/dist-esm/react-components/src/components/VideoGallery.js +12 -7
  42. package/dist/dist-esm/react-components/src/components/VideoGallery.js.map +1 -1
  43. package/dist/dist-esm/react-components/src/components/VideoTile.js +1 -1
  44. package/dist/dist-esm/react-components/src/components/VideoTile.js.map +1 -1
  45. package/dist/dist-esm/react-components/src/components/styles/VerticalGallery.styles.js +1 -1
  46. package/dist/dist-esm/react-components/src/components/styles/VerticalGallery.styles.js.map +1 -1
  47. package/dist/dist-esm/react-components/src/components/styles/VideoGallery.styles.d.ts +4 -0
  48. package/dist/dist-esm/react-components/src/components/styles/VideoGallery.styles.js +6 -0
  49. package/dist/dist-esm/react-components/src/components/styles/VideoGallery.styles.js.map +1 -1
  50. package/dist/dist-esm/react-composites/src/composites/CallComposite/Strings.d.ts +4 -0
  51. package/dist/dist-esm/react-composites/src/composites/CallComposite/Strings.js.map +1 -1
  52. package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/AzureCommunicationCallAdapter.js +3 -3
  53. package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/AzureCommunicationCallAdapter.js.map +1 -1
  54. package/dist/dist-esm/react-composites/src/composites/CallComposite/pages/TransferPage.js +24 -11
  55. package/dist/dist-esm/react-composites/src/composites/CallComposite/pages/TransferPage.js.map +1 -1
  56. package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/TransferPage.styles.d.ts +7 -0
  57. package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/TransferPage.styles.js +4 -0
  58. package/dist/dist-esm/react-composites/src/composites/CallComposite/styles/TransferPage.styles.js.map +1 -1
  59. package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.d.ts +0 -9
  60. package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.js +1 -14
  61. package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.js.map +1 -1
  62. package/dist/dist-esm/react-composites/src/composites/ChatComposite/adapter/AzureCommunicationChatAdapter.js +2 -2
  63. package/dist/dist-esm/react-composites/src/composites/ChatComposite/adapter/AzureCommunicationChatAdapter.js.map +1 -1
  64. package/dist/dist-esm/react-composites/src/composites/localization/locales/en-US/strings.json +2 -1
  65. package/package.json +8 -8
@@ -163,11 +163,22 @@ const _toCommunicationIdentifier = (id) => {
163
163
  }
164
164
  return id;
165
165
  };
166
+ /**
167
+ * Check if an object is identifier.
168
+ *
169
+ * @internal
170
+ */
171
+ const _isValidIdentifier = (identifier) => {
172
+ return (communicationCommon.isCommunicationUserIdentifier(identifier) ||
173
+ communicationCommon.isPhoneNumberIdentifier(identifier) ||
174
+ communicationCommon.isMicrosoftTeamsUserIdentifier(identifier) ||
175
+ communicationCommon.isUnknownIdentifier(identifier));
176
+ };
166
177
 
167
178
  // Copyright (c) Microsoft Corporation.
168
179
  // Licensed under the MIT license.
169
180
  // GENERATED FILE. DO NOT EDIT MANUALLY.
170
- var telemetryVersion = '1.5.1-alpha-202306180015';
181
+ var telemetryVersion = '1.5.1-alpha-202306210014';
171
182
 
172
183
  // Copyright (c) Microsoft Corporation.
173
184
  /**
@@ -6304,10 +6315,14 @@ const getTagClosingTagInfo = (tag) => {
6304
6315
  * @returns Updated HTML and selection index if the selection index should be set.
6305
6316
  */
6306
6317
  const updateHTML = (props) => {
6307
- const { htmlText, oldPlainText, newPlainText, tags, startIndex, oldPlainTextEndIndex, change, mentionTrigger } = props;
6318
+ const { htmlText, oldPlainText, tags, startIndex, oldPlainTextEndIndex, change, mentionTrigger } = props;
6308
6319
  if (tags.length === 0 || (startIndex === 0 && oldPlainTextEndIndex === oldPlainText.length - 1)) {
6309
6320
  // no tags added yet or the whole text is changed
6310
- return { updatedHTML: newPlainText, updatedSelectionIndex: undefined };
6321
+ const changeWithSkippedChars = escapeHTMLChars(change);
6322
+ const updatedHTML = escapeHTMLChars(oldPlainText.substring(0, startIndex)) +
6323
+ changeWithSkippedChars +
6324
+ escapeHTMLChars(oldPlainText.substring(oldPlainTextEndIndex));
6325
+ return { updatedHTML, updatedSelectionIndex: undefined };
6311
6326
  }
6312
6327
  let result = '';
6313
6328
  let lastProcessedHTMLIndex = 0;
@@ -6317,7 +6332,7 @@ const updateHTML = (props) => {
6317
6332
  // e.g.: change is after and partially in tag => change will be added after the tag and outdated text in the tag will be removed
6318
6333
  // e.g.: change is on the beginning of the tag => change will be added before the tag
6319
6334
  // e.g.: change is on the end of the tag => change will be added to the tag if it's not mention and after the tag if it's mention
6320
- let processedChange = change;
6335
+ let processedChange = escapeHTMLChars(change);
6321
6336
  // end tag plain text index of the last processed tag
6322
6337
  let lastProcessedPlainTextTagEndIndex = 0;
6323
6338
  // as some tags/text can be removed fully, selection should be updated correctly
@@ -6339,13 +6354,13 @@ const updateHTML = (props) => {
6339
6354
  if (startIndex <= tag.plainTextBeginIndex) {
6340
6355
  // change start is before the open tag
6341
6356
  // Math.max(lastProcessedPlainTextTagEndIndex, startIndex) is used as startIndex may not be in [[previous tag].plainTextEndIndex - tag.plainTextBeginIndex] range
6342
- const startChangeDiff = tag.plainTextBeginIndex - Math.max(lastProcessedPlainTextTagEndIndex, startIndex);
6357
+ const startChangeDiff = getChangeDiff(oldPlainText, Math.max(lastProcessedPlainTextTagEndIndex, startIndex), tag.plainTextBeginIndex);
6343
6358
  result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex - startChangeDiff) + processedChange;
6344
6359
  processedChange = '';
6345
6360
  if (oldPlainTextEndIndex <= tag.plainTextBeginIndex) {
6346
6361
  // the whole change is before tag start
6347
6362
  // mentionTag length can be ignored here as the change is before the tag
6348
- const endChangeDiff = tag.plainTextBeginIndex - oldPlainTextEndIndex;
6363
+ const endChangeDiff = getChangeDiff(oldPlainText, oldPlainTextEndIndex, tag.plainTextBeginIndex);
6349
6364
  lastProcessedHTMLIndex = tag.openTagIndex - endChangeDiff;
6350
6365
  // the change is handled; exit
6351
6366
  break;
@@ -6375,13 +6390,13 @@ const updateHTML = (props) => {
6375
6390
  if (startIndex !== tag.plainTextBeginIndex && startIndex !== closingTagInfo.plainTextEndIndex) {
6376
6391
  // mention tag should be deleted when user tries to edit it in the middle
6377
6392
  result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
6378
- changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
6393
+ changeNewEndIndex = tag.plainTextBeginIndex + unEscapeHtmlCharacters(processedChange).length;
6379
6394
  lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
6380
6395
  }
6381
6396
  else if (startIndex === tag.plainTextBeginIndex) {
6382
6397
  // non empty change at the beginning of the mention tag to be added before the mention tag
6383
6398
  result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
6384
- changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
6399
+ changeNewEndIndex = tag.plainTextBeginIndex + unEscapeHtmlCharacters(processedChange).length;
6385
6400
  lastProcessedHTMLIndex = tag.openTagIndex;
6386
6401
  }
6387
6402
  else if (startIndex === closingTagInfo.plainTextEndIndex) {
@@ -6389,12 +6404,13 @@ const updateHTML = (props) => {
6389
6404
  result +=
6390
6405
  htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength) +
6391
6406
  processedChange;
6392
- changeNewEndIndex = closingTagInfo.plainTextEndIndex + processedChange.length;
6407
+ changeNewEndIndex = closingTagInfo.plainTextEndIndex + unEscapeHtmlCharacters(processedChange).length;
6393
6408
  lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
6394
6409
  }
6395
6410
  processedChange = '';
6396
6411
  }
6397
6412
  else {
6413
+ // When change is empty, it means that this change is a deletion
6398
6414
  const updateMentionTagResult = handleMentionTagUpdate({
6399
6415
  htmlText,
6400
6416
  oldPlainText,
@@ -6422,7 +6438,6 @@ const updateHTML = (props) => {
6422
6438
  const updatedContent = updateHTML({
6423
6439
  htmlText: tag.content,
6424
6440
  oldPlainText,
6425
- newPlainText,
6426
6441
  tags: tag.subTags,
6427
6442
  startIndex,
6428
6443
  oldPlainTextEndIndex,
@@ -6434,13 +6449,13 @@ const updateHTML = (props) => {
6434
6449
  }
6435
6450
  else {
6436
6451
  // no subtags
6437
- const startChangeDiff = startIndex - tag.plainTextBeginIndex;
6452
+ const startChangeDiff = getChangeDiff(oldPlainText, tag.plainTextBeginIndex, startIndex);
6438
6453
  result +=
6439
6454
  htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff) +
6440
6455
  processedChange;
6441
6456
  processedChange = '';
6442
6457
  if (oldPlainTextEndIndex < closingTagInfo.plainTextEndIndex) {
6443
- const endChangeDiff = oldPlainTextEndIndex - tag.plainTextBeginIndex;
6458
+ const endChangeDiff = getChangeDiff(oldPlainText, tag.plainTextBeginIndex, oldPlainTextEndIndex);
6444
6459
  lastProcessedHTMLIndex = tag.openTagIndex + tag.openTagBody.length + endChangeDiff;
6445
6460
  }
6446
6461
  else if (oldPlainTextEndIndex === closingTagInfo.plainTextEndIndex) {
@@ -6479,7 +6494,6 @@ const updateHTML = (props) => {
6479
6494
  const updatedContent = updateHTML({
6480
6495
  htmlText: tag.content,
6481
6496
  oldPlainText,
6482
- newPlainText,
6483
6497
  tags: tag.subTags,
6484
6498
  startIndex,
6485
6499
  oldPlainTextEndIndex,
@@ -6539,7 +6553,6 @@ const updateHTML = (props) => {
6539
6553
  const updatedContent = updateHTML({
6540
6554
  htmlText: tag.content,
6541
6555
  oldPlainText,
6542
- newPlainText,
6543
6556
  tags: tag.subTags,
6544
6557
  startIndex,
6545
6558
  oldPlainTextEndIndex,
@@ -6555,7 +6568,7 @@ const updateHTML = (props) => {
6555
6568
  htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length) + processedChange;
6556
6569
  processedChange = '';
6557
6570
  // oldPlainTextEndIndex already includes mentionTag length
6558
- const endChangeDiff = closingTagInfo.plainTextEndIndex - oldPlainTextEndIndex;
6571
+ const endChangeDiff = getChangeDiff(oldPlainText, oldPlainTextEndIndex, closingTagInfo.plainTextEndIndex);
6559
6572
  // as change may be before the end of the tag, we need to add the rest of the tag
6560
6573
  lastProcessedHTMLIndex = closingTagInfo.closeTagIdx - endChangeDiff;
6561
6574
  }
@@ -6567,9 +6580,9 @@ const updateHTML = (props) => {
6567
6580
  if (i === tags.length - 1 && oldPlainTextEndIndex >= closingTagInfo.plainTextEndIndex) {
6568
6581
  // the last tag should handle the end of the change if needed
6569
6582
  // oldPlainTextEndIndex already includes mentionTag length
6570
- const endChangeDiff = oldPlainTextEndIndex - closingTagInfo.plainTextEndIndex;
6583
+ const endChangeDiff = getChangeDiff(oldPlainText, closingTagInfo.plainTextEndIndex, oldPlainTextEndIndex);
6571
6584
  if (startIndex >= closingTagInfo.plainTextEndIndex) {
6572
- const startChangeDiff = startIndex - closingTagInfo.plainTextEndIndex;
6585
+ const startChangeDiff = getChangeDiff(oldPlainText, closingTagInfo.plainTextEndIndex, startIndex);
6573
6586
  result +=
6574
6587
  htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength + startChangeDiff) + processedChange;
6575
6588
  }
@@ -6719,17 +6732,18 @@ const textToTagParser = (text, trigger) => {
6719
6732
  if (!foundHtmlTag) {
6720
6733
  if (parseIndex !== 0) {
6721
6734
  // Add the remaining text to the plain text representation
6722
- plainTextRepresentation += text.substring(parseIndex);
6735
+ const newText = text.substring(parseIndex);
6736
+ plainTextRepresentation += unEscapeHtmlCharacters(newText);
6723
6737
  }
6724
6738
  else {
6725
- plainTextRepresentation = text;
6739
+ plainTextRepresentation = unEscapeHtmlCharacters(text);
6726
6740
  }
6727
6741
  break;
6728
6742
  }
6729
6743
  if (foundHtmlTag.type === 'open' || foundHtmlTag.type === 'self-closing') {
6730
6744
  const nextTag = parseOpenTag(foundHtmlTag.content, foundHtmlTag.startIdx);
6731
6745
  // Add the plain text between the last tag and this one found
6732
- plainTextRepresentation += text.substring(parseIndex, foundHtmlTag.startIdx);
6746
+ plainTextRepresentation += unEscapeHtmlCharacters(text.substring(parseIndex, foundHtmlTag.startIdx));
6733
6747
  nextTag.plainTextBeginIndex = plainTextRepresentation.length;
6734
6748
  if (foundHtmlTag.type === 'open') {
6735
6749
  tagParseStack.push(nextTag);
@@ -6755,14 +6769,14 @@ const textToTagParser = (text, trigger) => {
6755
6769
  plainTextRepresentation.slice(currentOpenTag.plainTextBeginIndex);
6756
6770
  }
6757
6771
  if (!currentOpenTag.subTags) {
6758
- plainTextRepresentation += currentOpenTag.content;
6772
+ plainTextRepresentation += unEscapeHtmlCharacters(currentOpenTag.content);
6759
6773
  }
6760
6774
  else if (currentOpenTag.subTags.length > 0) {
6761
6775
  // Add text after the last tag
6762
6776
  const lastSubTag = currentOpenTag.subTags[currentOpenTag.subTags.length - 1];
6763
6777
  const startOfRemainingText = ((_a = lastSubTag.closingTagIndex) !== null && _a !== void 0 ? _a : lastSubTag.openTagIndex) + lastSubTag.tagType.length + 3;
6764
6778
  const trailingText = currentOpenTag.content.substring(startOfRemainingText);
6765
- plainTextRepresentation += trailingText;
6779
+ plainTextRepresentation += unEscapeHtmlCharacters(trailingText);
6766
6780
  }
6767
6781
  currentOpenTag.plainTextEndIndex = plainTextRepresentation.length;
6768
6782
  addTag(currentOpenTag, tagParseStack, tags);
@@ -6850,6 +6864,32 @@ const addTag = (tag, parseStack, tags) => {
6850
6864
  }
6851
6865
  }
6852
6866
  };
6867
+ // We should revisit this in the future when we support other text such as rich text editing.
6868
+ const escapeHTMLChars = (text) => {
6869
+ const mentionRegex = new RegExp(`<${MSFT_MENTION_TAG}(.*?)>(.*?)</${MSFT_MENTION_TAG}>`, 'i');
6870
+ if (!text.match(mentionRegex)) {
6871
+ return text
6872
+ .replace(/&(?![A-Z]+;)/gi, '&amp;')
6873
+ .replace(/</g, '&lt;')
6874
+ .replace(/>/g, '&gt;');
6875
+ }
6876
+ return text;
6877
+ };
6878
+ const getChangeDiff = (plainText, startIndex, endIndex) => {
6879
+ return endIndex - startIndex + getLengthDiffForEscapedHtmlChars(plainText, startIndex, endIndex);
6880
+ };
6881
+ const getLengthDiffForEscapedHtmlChars = (text, startIndex, endIndex) => {
6882
+ var _a, _b;
6883
+ const subText = text.substring(startIndex, endIndex);
6884
+ const escapedAngleBracketCount = ((_a = subText.match(/(<)|(>)/g)) === null || _a === void 0 ? void 0 : _a.length) || 0;
6885
+ let escapedCharLength = escapedAngleBracketCount * ('&lt;'.length - '<'.length);
6886
+ const escapedAmpersandCount = ((_b = subText.match(/&/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
6887
+ escapedCharLength += escapedAmpersandCount * ('&amp;'.length - '&'.length);
6888
+ return escapedCharLength;
6889
+ };
6890
+ const unEscapeHtmlCharacters = (text) => {
6891
+ return text.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
6892
+ };
6853
6893
 
6854
6894
  // Copyright (c) Microsoft Corporation.
6855
6895
  /**
@@ -7117,13 +7157,11 @@ const TextFieldWithMention = (props) => {
7117
7157
  const oldPlainText = inputTextValue;
7118
7158
  const mention = htmlStringForMentionSuggestion(suggestion, localeStrings);
7119
7159
  // update plain text with the mention html text
7120
- const newPlainText = inputTextValue.substring(0, currentTriggerStartIndex) + mention + inputTextValue.substring(selectionEnd);
7121
7160
  const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : DEFAULT_MENTION_TRIGGER;
7122
7161
  // update html text with updated plain text
7123
7162
  const updatedContent = updateHTML({
7124
7163
  htmlText: textValue,
7125
7164
  oldPlainText,
7126
- newPlainText,
7127
7165
  tags: tagsValue,
7128
7166
  startIndex: currentTriggerStartIndex,
7129
7167
  oldPlainTextEndIndex: selectionEnd,
@@ -7438,44 +7476,32 @@ const TextFieldWithMention = (props) => {
7438
7476
  }
7439
7477
  }
7440
7478
  }
7441
- let result = '';
7442
- if (tagsValue.length === 0) {
7443
- // no tags in the string and newValue should be used as a result string
7444
- result = newValue;
7445
- }
7446
- else {
7447
- // there are tags in the text value and htmlTextValue is html string
7448
- // find diff between old and new text
7449
- const { changeStart, oldChangeEnd, newChangeEnd } = findStringsDiffIndexes({
7450
- oldText: inputTextValue,
7451
- newText: newValue,
7452
- previousSelectionStart: previousSelectionStartValue,
7453
- previousSelectionEnd: previousSelectionEndValue,
7454
- currentSelectionStart: currentSelectionStartValue,
7455
- currentSelectionEnd: currentSelectionEndValue
7456
- });
7457
- const change = newValue.substring(changeStart, newChangeEnd);
7458
- // get updated html string
7459
- const updatedContent = updateHTML({
7460
- htmlText: htmlTextValue,
7461
- oldPlainText: inputTextValue,
7462
- newPlainText: newValue,
7463
- tags: tagsValue,
7464
- startIndex: changeStart,
7465
- oldPlainTextEndIndex: oldChangeEnd,
7466
- change,
7467
- mentionTrigger: triggerText
7468
- });
7469
- result = updatedContent.updatedHTML;
7470
- // update caret index if needed
7471
- if (updatedContent.updatedSelectionIndex !== undefined) {
7472
- setCaretIndex(updatedContent.updatedSelectionIndex);
7473
- setSelectionEndValue(updatedContent.updatedSelectionIndex);
7474
- setSelectionStartValue(updatedContent.updatedSelectionIndex);
7475
- }
7476
- }
7477
- onChange && onChange(event, result);
7478
- }), [onChange, mentionLookupOptions, setCaretIndex, setCaretPosition, updateMentionSuggestions, debouncedQueryUpdate]);
7479
+ const { changeStart, oldChangeEnd, newChangeEnd } = findStringsDiffIndexes({
7480
+ oldText: inputTextValue,
7481
+ newText: newValue,
7482
+ previousSelectionStart: previousSelectionStartValue,
7483
+ previousSelectionEnd: previousSelectionEndValue,
7484
+ currentSelectionStart: currentSelectionStartValue,
7485
+ currentSelectionEnd: currentSelectionEndValue
7486
+ });
7487
+ const change = newValue.substring(changeStart, newChangeEnd);
7488
+ const updatedContent = updateHTML({
7489
+ htmlText: htmlTextValue,
7490
+ oldPlainText: inputTextValue,
7491
+ tags: tagsValue,
7492
+ startIndex: changeStart,
7493
+ oldPlainTextEndIndex: oldChangeEnd,
7494
+ change,
7495
+ mentionTrigger: triggerText
7496
+ });
7497
+ // update caret index if needed
7498
+ if (updatedContent.updatedSelectionIndex !== undefined) {
7499
+ setCaretIndex(updatedContent.updatedSelectionIndex);
7500
+ setSelectionEndValue(updatedContent.updatedSelectionIndex);
7501
+ setSelectionStartValue(updatedContent.updatedSelectionIndex);
7502
+ }
7503
+ onChange && onChange(event, updatedContent.updatedHTML);
7504
+ }), [debouncedQueryUpdate, mentionLookupOptions, onChange, updateMentionSuggestions]);
7479
7505
  // Adjust the selection range based on a mouse / touch interaction
7480
7506
  const handleOnMove = React.useCallback(({ event, selectionStartValue, selectionEndValue, interactionStartSelection, shouldHandleMoveEvent }) => {
7481
7507
  if (shouldHandleMoveEvent &&
@@ -7640,7 +7666,12 @@ const InputBoxComponent = (props) => {
7640
7666
  if (props.mentionLookupOptions) {
7641
7667
  return React__default['default'].createElement(TextFieldWithMention, Object.assign({}, textFieldWithMentionProps));
7642
7668
  }
7643
- return (React__default['default'].createElement(react.TextField, Object.assign({}, textFieldProps, { "data-ui-id": dataUiId, value: textValue, onChange: onChange, onKeyDown: onTextFieldKeyDown })));
7669
+ return (React__default['default'].createElement(react.TextField, Object.assign({}, textFieldProps, { "data-ui-id": dataUiId, value: textValue, onChange: onChange, onKeyDown: onTextFieldKeyDown, onFocus: (e) => {
7670
+ // Fix for setting the cursor to the correct position when multiline is true
7671
+ // This approach should be reviewed during migration to FluentUI v9
7672
+ e.currentTarget.value = '';
7673
+ e.currentTarget.value = textValue;
7674
+ } })));
7644
7675
  };
7645
7676
  return (React__default['default'].createElement(react.Stack, { className: mergedRootStyle },
7646
7677
  React__default['default'].createElement("div", { className: mergedTextContainerStyle }, renderTextField())));
@@ -11271,7 +11302,7 @@ const VideoTile = (props) => {
11271
11302
  }
11272
11303
  const currentObserver = observer.current;
11273
11304
  return () => currentObserver.disconnect();
11274
- }, [observer, videoTileRef]);
11305
+ }, [videoTileRef]);
11275
11306
  /* @conditional-compile-remove(pinned-participants) */
11276
11307
  const useLongPressProps = React.useMemo(() => {
11277
11308
  return {
@@ -11630,6 +11661,12 @@ const localVideoCameraCycleButtonStyles = (theme) => {
11630
11661
  }
11631
11662
  };
11632
11663
  };
11664
+ /**
11665
+ * @private
11666
+ */
11667
+ const localVideoTileContainerStyles = {
11668
+ root: { width: '100%', height: '100%' }
11669
+ };
11633
11670
 
11634
11671
  // Copyright (c) Microsoft Corporation.
11635
11672
  /**
@@ -11772,7 +11809,7 @@ const DEFAULT_MAX_OVERFLOW_GALLERY_DOMINANT_SPEAKERS = 6;
11772
11809
  const _useOrganizedParticipants = (props) => {
11773
11810
  const visibleGridParticipants = React.useRef([]);
11774
11811
  const visibleOverflowGalleryParticipants = React.useRef([]);
11775
- const { remoteParticipants = [], dominantSpeakers = [], maxRemoteVideoStreams, maxOverflowGalleryDominantSpeakers = DEFAULT_MAX_OVERFLOW_GALLERY_DOMINANT_SPEAKERS, isScreenShareActive = false, pinnedParticipantUserIds = [] } = props;
11812
+ const { remoteParticipants = [], localParticipant, dominantSpeakers = [], maxRemoteVideoStreams, maxOverflowGalleryDominantSpeakers = DEFAULT_MAX_OVERFLOW_GALLERY_DOMINANT_SPEAKERS, isScreenShareActive = false, pinnedParticipantUserIds = [] } = props;
11776
11813
  const videoParticipants = remoteParticipants.filter((p) => { var _a; return (_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable; });
11777
11814
  visibleGridParticipants.current =
11778
11815
  pinnedParticipantUserIds.length > 0 || isScreenShareActive
@@ -11810,7 +11847,13 @@ const _useOrganizedParticipants = (props) => {
11810
11847
  ]);
11811
11848
  const gridParticipants = getGridParticipants();
11812
11849
  const getOverflowGalleryRemoteParticipants = React.useCallback(() => {
11813
- if (isScreenShareActive) {
11850
+ if (isScreenShareActive && localParticipant) {
11851
+ const localParticipantPlusOverflow = [localParticipant].concat(visibleGridParticipants.current.concat(visibleOverflowGalleryParticipants.current));
11852
+ // If screen sharing is active, assign video and audio participants as overflow gallery participants
11853
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
11854
+ return localParticipantPlusOverflow.concat(callingParticipants);
11855
+ }
11856
+ else if (isScreenShareActive) {
11814
11857
  // If screen sharing is active, assign video and audio participants as overflow gallery participants
11815
11858
  /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
11816
11859
  return visibleGridParticipants.current.concat(visibleOverflowGalleryParticipants.current.concat(callingParticipants));
@@ -11825,7 +11868,8 @@ const _useOrganizedParticipants = (props) => {
11825
11868
  }
11826
11869
  }, [
11827
11870
  /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */ callingParticipants,
11828
- isScreenShareActive
11871
+ isScreenShareActive,
11872
+ localParticipant
11829
11873
  ]);
11830
11874
  const overflowGalleryParticipants = getOverflowGalleryRemoteParticipants();
11831
11875
  return { gridParticipants, overflowGalleryParticipants: overflowGalleryParticipants };
@@ -11978,9 +12022,12 @@ const HorizontalGallery = (props) => {
11978
12022
  const firstIndexOfCurrentPage = page * childrenPerPage;
11979
12023
  const clippedPage = firstIndexOfCurrentPage < numberOfChildren - 1 ? page : lastPage;
11980
12024
  const childrenOnCurrentPage = React.useMemo(() => {
11981
- return indexesArray[clippedPage].map((index) => {
11982
- return React__default['default'].Children.toArray(children)[index];
11983
- });
12025
+ if (indexesArray[0] !== undefined) {
12026
+ return indexesArray[clippedPage].map((index) => {
12027
+ return React__default['default'].Children.toArray(children)[index];
12028
+ });
12029
+ }
12030
+ return [];
11984
12031
  }, [indexesArray, clippedPage, children]);
11985
12032
  const showButtons = numberOfChildren > childrenPerPage;
11986
12033
  const disablePreviousButton = page === 0;
@@ -12036,10 +12083,13 @@ const LOCAL_VIDEO_TILE_ZINDEX = 2;
12036
12083
  /**
12037
12084
  * @private
12038
12085
  */
12039
- const localVideoTileContainerStyle = (theme, localVideoTileSizeRem) => {
12086
+ const localVideoTileContainerStyle = (theme, localVideoTileSizeRem, screenSharePresent) => {
12087
+ console.log(screenSharePresent);
12040
12088
  return {
12041
- minWidth: `${localVideoTileSizeRem.width}rem`,
12042
- minHeight: `${localVideoTileSizeRem.height}rem`,
12089
+ width: screenSharePresent ? `${localVideoTileSizeRem.width}rem` : '',
12090
+ height: screenSharePresent ? `${localVideoTileSizeRem.height}rem` : '',
12091
+ minWidth: screenSharePresent ? '' : `${localVideoTileSizeRem.width}rem`,
12092
+ minHeight: screenSharePresent ? '' : `${localVideoTileSizeRem.height}rem`,
12043
12093
  position: 'absolute',
12044
12094
  bottom: `${localVideoTileOuterPaddingRem}rem`,
12045
12095
  borderRadius: theme.effects.roundedCorner4,
@@ -12366,7 +12416,7 @@ const childrenContainerStyle = (pageControlBarHeight) => {
12366
12416
  */
12367
12417
  const rootStyle = {
12368
12418
  height: '100%',
12369
- width: '100%',
12419
+ width: 'inherit',
12370
12420
  gap: `${VERTICAL_GALLERY_GAP}rem`,
12371
12421
  position: 'relative'
12372
12422
  };
@@ -12435,9 +12485,12 @@ const VerticalGallery = (props) => {
12435
12485
  const firstIndexOfCurrentPage = (page - 1) * childrenPerPage;
12436
12486
  const clippedPage = firstIndexOfCurrentPage < numberOfChildren - 1 ? page : lastPage;
12437
12487
  const childrenOnCurrentPage = React.useMemo(() => {
12438
- return indexesArray[clippedPage - 1].map((index) => {
12439
- return React__default['default'].Children.toArray(children)[index];
12440
- });
12488
+ if (indexesArray[0] !== undefined) {
12489
+ return indexesArray[clippedPage - 1].map((index) => {
12490
+ return React__default['default'].Children.toArray(children)[index];
12491
+ });
12492
+ }
12493
+ return;
12441
12494
  }, [indexesArray, clippedPage, children]);
12442
12495
  const showButtons = numberOfChildren > childrenPerPage;
12443
12496
  const onPreviousButtonClick = () => {
@@ -12521,13 +12574,14 @@ const VerticalGalleryControlBar = (props) => {
12521
12574
  * @beta
12522
12575
  */
12523
12576
  const ResponsiveVerticalGallery = (props) => {
12577
+ var _a;
12524
12578
  const { children, containerStyles, verticalGalleryStyles, gapHeightRem, controlBarHeightRem, isShort, onFetchTilesToRender, onChildrenPerPageChange } = props;
12525
12579
  const containerRef = React.useRef(null);
12526
12580
  const containerHeight = _useContainerHeight(containerRef);
12527
12581
  const topPadding = containerRef.current ? parseFloat(getComputedStyle(containerRef.current).paddingTop) : 0;
12528
12582
  const bottomPadding = containerRef.current ? parseFloat(getComputedStyle(containerRef.current).paddingBottom) : 0;
12529
12583
  const childrenPerPage = calculateVerticalChildrenPerPage({
12530
- numberOfChildren: React__default['default'].Children.count(children),
12584
+ numberOfChildren: (_a = React__default['default'].Children.count(children)) !== null && _a !== void 0 ? _a : 0,
12531
12585
  containerHeight: (containerHeight !== null && containerHeight !== void 0 ? containerHeight : 0) - topPadding - bottomPadding,
12532
12586
  gapHeightRem,
12533
12587
  controlBarHeight: controlBarHeightRem !== null && controlBarHeightRem !== void 0 ? controlBarHeightRem : 2,
@@ -12621,16 +12675,16 @@ const OverflowGallery = (props) => {
12621
12675
  ]);
12622
12676
  /* @conditional-compile-remove(vertical-gallery) */
12623
12677
  if (overflowGalleryPosition === 'VerticalRight') {
12624
- return (React__default['default'].createElement(ResponsiveVerticalGallery, { key: "responsive-vertical-gallery", containerStyles: containerStyles, verticalGalleryStyles: galleryStyles, controlBarHeightRem: HORIZONTAL_GALLERY_BUTTON_WIDTH, gapHeightRem: HORIZONTAL_GALLERY_GAP, isShort: isShort, onFetchTilesToRender: onFetchTilesToRender, onChildrenPerPageChange: onChildrenPerPageChange }, overflowGalleryElements));
12678
+ return (React__default['default'].createElement(ResponsiveVerticalGallery, { key: "responsive-vertical-gallery", containerStyles: containerStyles, verticalGalleryStyles: galleryStyles, controlBarHeightRem: HORIZONTAL_GALLERY_BUTTON_WIDTH, gapHeightRem: HORIZONTAL_GALLERY_GAP, isShort: isShort, onFetchTilesToRender: onFetchTilesToRender, onChildrenPerPageChange: onChildrenPerPageChange }, overflowGalleryElements ? overflowGalleryElements : [React__default['default'].createElement(React__default['default'].Fragment, null)]));
12625
12679
  }
12626
12680
  /* @conditional-compile-remove(pinned-participants) */
12627
12681
  if (isNarrow) {
12628
12682
  // There are no pages for ScrollableHorizontalGallery so we will approximate the first 3 remote
12629
12683
  // participant tiles are visible
12630
12684
  onChildrenPerPageChange === null || onChildrenPerPageChange === void 0 ? void 0 : onChildrenPerPageChange(3);
12631
- return (React__default['default'].createElement(ScrollableHorizontalGallery, { horizontalGalleryElements: overflowGalleryElements, onFetchTilesToRender: onFetchTilesToRender, key: "scrollable-horizontal-gallery" }));
12685
+ return (React__default['default'].createElement(ScrollableHorizontalGallery, { horizontalGalleryElements: overflowGalleryElements ? overflowGalleryElements : [React__default['default'].createElement(React__default['default'].Fragment, null)], onFetchTilesToRender: onFetchTilesToRender, key: "scrollable-horizontal-gallery" }));
12632
12686
  }
12633
- return (React__default['default'].createElement(ResponsiveHorizontalGallery, { key: "responsive-horizontal-gallery", containerStyles: containerStyles, onFetchTilesToRender: onFetchTilesToRender, horizontalGalleryStyles: galleryStyles, buttonWidthRem: HORIZONTAL_GALLERY_BUTTON_WIDTH, gapWidthRem: HORIZONTAL_GALLERY_GAP, onChildrenPerPageChange: onChildrenPerPageChange }, overflowGalleryElements));
12687
+ return (React__default['default'].createElement(ResponsiveHorizontalGallery, { key: "responsive-horizontal-gallery", containerStyles: containerStyles, onFetchTilesToRender: onFetchTilesToRender, horizontalGalleryStyles: galleryStyles, buttonWidthRem: HORIZONTAL_GALLERY_BUTTON_WIDTH, gapWidthRem: HORIZONTAL_GALLERY_GAP, onChildrenPerPageChange: onChildrenPerPageChange }, overflowGalleryElements ? overflowGalleryElements : [React__default['default'].createElement(React__default['default'].Fragment, null)]));
12634
12688
  };
12635
12689
 
12636
12690
  // Copyright (c) Microsoft Corporation.
@@ -12641,7 +12695,7 @@ const OverflowGallery = (props) => {
12641
12695
  * @private
12642
12696
  */
12643
12697
  const DefaultLayout = (props) => {
12644
- const { remoteParticipants = [], dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, parentWidth,
12698
+ const { remoteParticipants = [], localParticipant, dominantSpeakers, localVideoComponent, screenShareComponent, onRenderRemoteParticipant, styles, maxRemoteVideoStreams, parentWidth,
12645
12699
  /* @conditional-compile-remove(vertical-gallery) */
12646
12700
  parentHeight, pinnedParticipantUserIds = [],
12647
12701
  /* @conditional-compile-remove(vertical-gallery) */ overflowGalleryPosition = 'HorizontalBottom' } = props;
@@ -12650,14 +12704,16 @@ const DefaultLayout = (props) => {
12650
12704
  const isShort = parentHeight ? isShortHeight(parentHeight) : false;
12651
12705
  // This is for tracking the number of children in the first page of overflow gallery.
12652
12706
  // This number will be used for the maxOverflowGalleryDominantSpeakers when organizing the remote participants.
12707
+ // We need to add the local participant to the pinned participant count so we are placing the speakers correctly.
12653
12708
  const childrenPerPage = React.useRef(4);
12654
12709
  const { gridParticipants, overflowGalleryParticipants } = useOrganizedParticipants({
12655
12710
  remoteParticipants,
12711
+ localParticipant,
12656
12712
  dominantSpeakers,
12657
12713
  maxRemoteVideoStreams,
12658
12714
  isScreenShareActive: !!screenShareComponent,
12659
12715
  maxOverflowGalleryDominantSpeakers: screenShareComponent
12660
- ? childrenPerPage.current - (pinnedParticipantUserIds.length % childrenPerPage.current)
12716
+ ? childrenPerPage.current - ((pinnedParticipantUserIds.length + 1) % childrenPerPage.current)
12661
12717
  : childrenPerPage.current,
12662
12718
  /* @conditional-compile-remove(pinned-participants) */ pinnedParticipantUserIds
12663
12719
  });
@@ -13502,7 +13558,10 @@ const FloatingLocalVideoLayout = (props) => {
13502
13558
  const overflowGalleryTiles = overflowGalleryParticipants.map((p, i) => {
13503
13559
  var _a, _b;
13504
13560
  return onRenderRemoteParticipant(p, maxRemoteVideoStreams && maxRemoteVideoStreams >= 0
13505
- ? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) && indexesToRender.includes(i) && activeVideoStreams++ < maxRemoteVideoStreams
13561
+ ? ((_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable) &&
13562
+ indexesToRender &&
13563
+ indexesToRender.includes(i) &&
13564
+ activeVideoStreams++ < maxRemoteVideoStreams
13506
13565
  : (_b = p.videoStream) === null || _b === void 0 ? void 0 : _b.isAvailable);
13507
13566
  });
13508
13567
  const layerHostId = reactHooks.useId('layerhost');
@@ -13511,7 +13570,7 @@ const FloatingLocalVideoLayout = (props) => {
13511
13570
  return SMALL_FLOATING_MODAL_SIZE_REM;
13512
13571
  }
13513
13572
  /* @conditional-compile-remove(vertical-gallery) */
13514
- if (overflowGalleryTiles.length > 0 && overflowGalleryPosition === 'VerticalRight') {
13573
+ if ((overflowGalleryTiles.length > 0 || screenShareComponent) && overflowGalleryPosition === 'VerticalRight') {
13515
13574
  return isNarrow
13516
13575
  ? SMALL_FLOATING_MODAL_SIZE_REM
13517
13576
  : isShort
@@ -13519,25 +13578,26 @@ const FloatingLocalVideoLayout = (props) => {
13519
13578
  : VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM;
13520
13579
  }
13521
13580
  /*@conditional-compile-remove(click-to-call) */
13522
- if (overflowGalleryTiles.length > 0 && overflowGalleryPosition === 'HorizontalBottom') {
13581
+ if ((overflowGalleryTiles.length > 0 || screenShareComponent) && overflowGalleryPosition === 'HorizontalBottom') {
13523
13582
  return localVideoTileSize === '16:9' || !isNarrow ? LARGE_FLOATING_MODAL_SIZE_REM : SMALL_FLOATING_MODAL_SIZE_REM;
13524
13583
  }
13525
13584
  return LARGE_FLOATING_MODAL_SIZE_REM;
13526
13585
  }, [
13527
13586
  overflowGalleryTiles.length,
13528
13587
  isNarrow,
13588
+ screenShareComponent,
13529
13589
  /* @conditional-compile-remove(vertical-gallery) */ isShort,
13530
13590
  /* @conditional-compile-remove(vertical-gallery) */ overflowGalleryPosition,
13531
13591
  /* @conditional-compile-remove(click-to-call) */ localVideoTileSize
13532
13592
  ]);
13533
- const wrappedLocalVideoComponent = localVideoComponent && shouldFloatLocalVideo ? (
13593
+ const wrappedLocalVideoComponent = (localVideoComponent && shouldFloatLocalVideo) || (screenShareComponent && localVideoComponent) ? (
13534
13594
  // When we use showCameraSwitcherInLocalPreview it disables dragging to allow keyboard navigation.
13535
13595
  showCameraSwitcherInLocalPreview ? (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(localVideoTileWithControlsContainerStyle(theme, localVideoSizeRem), {
13536
13596
  boxShadow: theme.effects.elevation8,
13537
13597
  zIndex: LOCAL_VIDEO_TILE_ZINDEX
13538
- }) }, localVideoComponent)) : overflowGalleryTiles.length > 0 ? (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(localVideoTileContainerStyle(theme, localVideoSizeRem)) }, localVideoComponent)) : (React__default['default'].createElement(FloatingLocalVideo, { localVideoComponent: localVideoComponent, layerHostId: layerHostId, localVideoSizeRem: localVideoSizeRem, parentWidth: parentWidth, parentHeight: parentHeight }))) : undefined;
13598
+ }) }, localVideoComponent)) : overflowGalleryTiles.length > 0 || screenShareComponent ? (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(localVideoTileContainerStyle(theme, localVideoSizeRem, !!screenShareComponent)) }, localVideoComponent)) : (React__default['default'].createElement(FloatingLocalVideo, { localVideoComponent: localVideoComponent, layerHostId: layerHostId, localVideoSizeRem: localVideoSizeRem, parentWidth: parentWidth, parentHeight: parentHeight }))) : undefined;
13539
13599
  const overflowGallery = React.useMemo(() => {
13540
- if (overflowGalleryTiles.length === 0) {
13600
+ if (overflowGalleryTiles.length === 0 && !screenShareComponent) {
13541
13601
  return null;
13542
13602
  }
13543
13603
  return (React__default['default'].createElement(OverflowGallery
@@ -13554,6 +13614,7 @@ const FloatingLocalVideoLayout = (props) => {
13554
13614
  }, [
13555
13615
  isNarrow,
13556
13616
  /* @conditional-compile-remove(vertical-gallery) */ isShort,
13617
+ screenShareComponent,
13557
13618
  overflowGalleryTiles,
13558
13619
  styles === null || styles === void 0 ? void 0 : styles.horizontalGallery,
13559
13620
  /* @conditional-compile-remove(vertical-gallery) */ overflowGalleryPosition,
@@ -13670,7 +13731,7 @@ const VideoGallery = (props) => {
13670
13731
  root: { borderRadius: theme.effects.roundedCorner4 }
13671
13732
  }, styles === null || styles === void 0 ? void 0 : styles.localVideo);
13672
13733
  const initialsName = !localParticipant.displayName ? '' : localParticipant.displayName;
13673
- return (React__default['default'].createElement(react.Stack, { key: "local-video-tile-key", tabIndex: 0, "aria-label": strings.localVideoMovementLabel, role: 'dialog' },
13734
+ return (React__default['default'].createElement(react.Stack, { styles: localVideoTileContainerStyles, key: "local-video-tile-key", tabIndex: 0, "aria-label": strings.localVideoMovementLabel, role: 'dialog' },
13674
13735
  React__default['default'].createElement(_LocalVideoTile, { userId: localParticipant.userId, onCreateLocalStreamView: onCreateLocalStreamView, onDisposeLocalStreamView: onDisposeLocalStreamView, isAvailable: (_a = localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable, isMuted: localParticipant.isMuted, renderElement: (_b = localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.videoStream) === null || _b === void 0 ? void 0 : _b.renderElement, displayName: isNarrow ? '' : strings.localVideoLabel, initialsName: initialsName, localVideoViewOptions: localVideoViewOptions, onRenderAvatar: onRenderAvatar, showLabel: !((shouldFloatLocalVideo && isNarrow) ||
13675
13736
  /*@conditional-compile-remove(click-to-call) */ localVideoTileSize === '9:16'), showMuteIndicator: showMuteIndicator, showCameraSwitcherInLocalPreview: showCameraSwitcherInLocalPreview, localVideoCameraCycleButtonProps: localVideoCameraCycleButtonProps, localVideoCameraSwitcherLabel: strings.localVideoCameraSwitcherLabel, localVideoSelectedDescription: strings.localVideoSelectedDescription, styles: localVideoTileStyles })));
13676
13737
  }, [
@@ -13732,11 +13793,13 @@ const VideoGallery = (props) => {
13732
13793
  /* @conditional-compile-remove(PSTN-calls) */
13733
13794
  participantState: participant.state,
13734
13795
  /* @conditional-compile-remove(pinned-participants) */
13735
- menuKind: remoteVideoTileMenuOptions
13736
- ? remoteVideoTileMenuOptions.kind === 'drawer'
13737
- ? 'drawer'
13738
- : 'contextual'
13739
- : undefined,
13796
+ menuKind: participant.userId === localParticipant.userId
13797
+ ? undefined
13798
+ : remoteVideoTileMenuOptions
13799
+ ? remoteVideoTileMenuOptions.kind === 'drawer'
13800
+ ? 'drawer'
13801
+ : 'contextual'
13802
+ : undefined,
13740
13803
  /* @conditional-compile-remove(pinned-participants) */
13741
13804
  drawerMenuHostId: drawerMenuHostId,
13742
13805
  /* @conditional-compile-remove(pinned-participants) */
@@ -13753,6 +13816,7 @@ const VideoGallery = (props) => {
13753
13816
  onCreateRemoteStreamView,
13754
13817
  onDisposeRemoteVideoStreamView,
13755
13818
  remoteVideoViewOptions,
13819
+ localParticipant,
13756
13820
  onRenderAvatar,
13757
13821
  showMuteIndicator,
13758
13822
  strings,
@@ -13773,6 +13837,7 @@ const VideoGallery = (props) => {
13773
13837
  : undefined;
13774
13838
  const layoutProps = React.useMemo(() => ({
13775
13839
  remoteParticipants,
13840
+ localParticipant,
13776
13841
  screenShareComponent,
13777
13842
  showCameraSwitcherInLocalPreview,
13778
13843
  maxRemoteVideoStreams,
@@ -13787,6 +13852,7 @@ const VideoGallery = (props) => {
13787
13852
  /* @conditional-compile-remove(click-to-call) */ localVideoTileSize
13788
13853
  }), [
13789
13854
  remoteParticipants,
13855
+ localParticipant,
13790
13856
  screenShareComponent,
13791
13857
  showCameraSwitcherInLocalPreview,
13792
13858
  maxRemoteVideoStreams,
@@ -18786,7 +18852,7 @@ const CallCompositeIcon = (props) => (React__default['default'].createElement(re
18786
18852
  */
18787
18853
  const CallWithChatCompositeIcon = (props) => (React__default['default'].createElement(react.FontIcon, Object.assign({}, props)));
18788
18854
 
18789
- var call$j={cameraLabel:"Camera",noCamerasLabel:"No cameras found",cameraPermissionDenied:"Your browser is blocking access to your camera",cameraTurnedOff:"Your camera is turned off",chatButtonLabel:"Chat",close:"Close",complianceBannerNowOnlyRecording:"You are now only recording this meeting.",complianceBannerNowOnlyTranscription:"You are now only transcribing this meeting.",complianceBannerRecordingAndTranscriptionSaved:"Recording and transcription are being saved.",complianceBannerRecordingAndTranscriptionStarted:"Recording and transcription have started.",complianceBannerRecordingAndTranscriptionStopped:"Recording and transcription have stopped.",complianceBannerRecordingSaving:"Recording is being saved.",complianceBannerRecordingStarted:"Recording has started.",complianceBannerRecordingStopped:"Recording has stopped.",complianceBannerTranscriptionStarted:"Transcription has started.",complianceBannerTranscriptionConsent:"By joining, you are giving consent for this meeting to be transcribed.",complianceBannerTranscriptionSaving:"Transcription is being saved.",complianceBannerTranscriptionStopped:"Transcription has stopped.",configurationPageTitle:"Start a call",copyInviteLinkButtonLabel:"Copy invite link",copyInviteLinkActionedAriaLabel:"Invite link copied",defaultPlaceHolder:"Select an option",dismissSidePaneButtonLabel:"Close",videoEffectsPaneTitle:"Effects",videoEffectsPaneBackgroundSelectionTitle:"Background",configurationPageVideoEffectsButtonLabel:"Effects",unableToStartVideoEffect:"Unable to apply video effect.",blurBackgroundEffectButtonLabel:"Blur",blurBackgroundTooltip:"Blur Background",removeBackgroundEffectButtonLabel:"None",removeBackgroundTooltip:"Remove Background",cameraOffBackgroundEffectWarningText:"Your camera is off. Turn on camera to see video effect.",failedToJoinCallDueToNoNetworkMoreDetails:"Call was disconnected due to a network issue. Check your connection and join again.",failedToJoinCallDueToNoNetworkTitle:"Call disconnected",failedToJoinTeamsMeetingReasonAccessDeniedMoreDetails:"You were not granted entry in the call. If this was a mistake, re-join the call.",failedToJoinTeamsMeetingReasonAccessDeniedTitle:"Dismissed from lobby",learnMore:"Learn more",leavingCallTitle:"Leaving...",leftCallMoreDetails:"If this was a mistake, re-join the call.",leftCallTitle:"You left the call",lobbyScreenConnectingToCallTitle:"Joining call",lobbyScreenWaitingToBeAdmittedTitle:"Waiting to be admitted",microphonePermissionDenied:"Your browser is blocking access to your microphone",microphoneToggleInLobbyNotAllowed:"Cannot mute or unmute while in lobby.",mutedMessage:"You're muted",networkReconnectMoreDetails:"Looks like something went wrong. We're trying to get back into the call.",networkReconnectTitle:"Hold on",deniedPermissionToRoomDetails:"You do not have permission to join this room.",deniedPermissionToRoomTitle:"Permission denied to room",peopleButtonLabel:"People",peoplePaneTitle:"People",peopleButtonTooltipOpen:"Show participants",peopleButtonTooltipClose:"Hide participants",peoplePaneSubTitle:"In this call",privacyPolicy:"Privacy policy",rejoinCallButtonLabel:"Re-join call",removedFromCallMoreDetails:"Another participant removed you from the call.",removedFromCallTitle:"You were removed",removeMenuLabel:"Remove",returnToCallButtonAriaDescription:"Return to Call",returnToCallButtonAriaLabel:"Back",roomNotFoundDetails:"Room ID provided is not valid.",roomNotFoundTitle:"Room not found",soundLabel:"Sound",noMicrophonesLabel:"No microphones found",noSpeakersLabel:"No speakers found",startCallButtonLabel:"Start call",openDialpadButtonLabel:"Dial phone number",peoplePaneAddPeopleButtonLabel:"Add People",dialpadStartCallButtonLabel:"Call",dialpadModalTitle:"Dial Phone Number",dialpadModalAriaLabel:"Dialpad",dialpadCloseModalButtonAriaLabel:"Close dialpad",moreButtonCallingLabel:"More",resumeCallButtonLabel:"Resume",resumingCallButtonLabel:"Resuming...",resumeCallButtonAriaLabel:"Resume call",resumingCallButtonAriaLabel:"Resume call",holdScreenLabel:"You're on hold",openDtmfDialpadLabel:"Show dialpad",dtmfDialpadPlaceholderText:"Enter number",outboundCallingNoticeString:"Calling...",participantJoinedNoticeString:"{displayName} joined",twoParticipantJoinedNoticeString:"{displayName1} and {displayName2} have joined",threeParticipantJoinedNoticeString:"{displayName1}, {displayName2} and {displayName3} have joined",participantLeftNoticeString:"{displayName} left",twoParticipantLeftNoticeString:"{displayName1} and {displayName2} have left",threeParticipantLeftNoticeString:"{displayName1}, {displayName2} and {displayName3} have left",unnamedParticipantString:"unnamed participant",manyUnnamedParticipantsJoined:"unnamed participant and {numOfParticipants} other participants joined",manyUnnamedParticipantsLeft:"unnamed participant and {numOfParticipants} other participants left",manyParticipantsJoined:"{displayName1}, {displayName2}, {displayName3} and {numOfParticipants} other participants joined",manyParticipantsLeft:"{displayName1}, {displayName2}, {displayName3} and {numOfParticipants} other participants left",liveCaptionsLabel:"Live captions",captionsSettingsLabel:"Caption settings",startCaptionsButtonOnLabel:"Turn on captions",startCaptionsButtonOffLabel:"Turn off captions",startCaptionsButtonTooltipOnContent:"Turn off captions",startCaptionsButtonTooltipOffContent:"Turn on captions",captionsSettingsModalTitle:"What language is being spoken?",captionsSettingsDropdownLabel:"Spoken language",captionsSettingsDropdownInfoText:"Language that everyone on this call is speaking.",captionsSettingsConfirmButtonLabel:"Confirm",captionsSettingsCancelButtonLabel:"Cancel",captionsSettingsModalAriaLabel:"Captions Setting Modal",captionsSettingsCloseModalButtonAriaLabel:"Close Captions Setting",captionsBannerMoreButtonCallingLabel:"More",captionsBannerMoreButtonTooltip:"More options",captionsAvailableLanguageStrings:{"ar-ae":"Arabic - U.A.E.","ar-sa":"Arabic - Saudi Arabia","da-dk":"Danish","de-de":"German - Germany","en-au":"English - Australia","en-ca":"English - Canada","en-gb":"English - United Kingdom","en-in":"English - India","en-nz":"English - New Zealand","en-us":"English - United States","es-es":"Spanish - Spain (Modern Sort)","es-mx":"Spanish - Mexico","fi-fi":"Finnish","fr-ca":"French - Canada","fr-fr":"French - France","hi-in":"Hindi","it-it":"Italian - Italy","ja-jp":"Japanese","ko-kr":"Korean","nb-no":"Norwegian (Bokmål)","nl-be":"Dutch - Belgium","nl-nl":"Dutch - Netherlands","pl-pl":"Polish","pt-br":"Portuguese - Brazil","ru-ru":"Russian","sv-se":"Swedish","zh-cn":"Chinese - People's Republic of China","zh-hk":"Chinese - Hong Kong SAR","cs-cz":"Czech","pt-pt":"Portuguese - Portugal","tr-tr":"Turkish","vi-vn":"Vietnamese","th-th":"Thai","he-il":"Hebrew","cy-gb":"Welsh","uk-ua":"Ukrainian","el-gr":"Greek","hu-hu":"Hungarian","ro-ro":"Romanian","sk-sk":"Slovak","zh-tw":"Chinese - Taiwan"},captionsBannerSpinnerText:"Starting captions...",transferPageTransferorText:"Transferring...",transferPageTransferTargetText:"Connecting...",transferPageUnknownTransferorDisplayName:"Unknown",transferPageUnknownTransferTargetDisplayName:"Unknown"};var chat$j={chatListHeader:"In this chat",uploadFile:"Upload File"};var callWithChat$j={chatButtonLabel:"Chat",chatButtonNewMessageNotificationLabel:"New Message",chatButtonTooltipClosedWithMessageCount:"Show chat ({unreadMessagesCount} unread)",chatButtonTooltipClose:"Hide chat",chatButtonTooltipOpen:"Show chat",chatPaneTitle:"Chat",copyInviteLinkButtonLabel:"Copy invite link",copyInviteLinkActionedAriaLabel:"Invite link copied",dismissSidePaneButtonLabel:"Close",moreDrawerAudioDeviceMenuTitle:"Audio Device",moreDrawerButtonLabel:"More options",moreDrawerButtonTooltip:"More options",moreDrawerMicrophoneMenuTitle:"Microphone",moreDrawerSpeakerMenuTitle:"Speaker",moreDrawerCaptionsMenuTitle:"Live captions",moreDrawerSpokenLanguageMenuTitle:"Spoken language",peopleButtonLabel:"People",peopleButtonTooltipOpen:"Show participants",peopleButtonTooltipClose:"Hide participants",peoplePaneSubTitle:"In this call",peoplePaneTitle:"People",pictureInPictureTileAriaLabel:"Video Feeds. Click to return to call screen.",removeMenuLabel:"Remove",openDialpadButtonLabel:"Dial phone number",returnToCallButtonAriaDescription:"Return to Call",returnToCallButtonAriaLabel:"Back",peoplePaneAddPeopleButtonLabel:"Add People",dialpadStartCallButtonLabel:"Call",dialpadModalTitle:"Dial Phone Number",dialpadModalAriaLabel:"Dialpad",dialpadCloseModalButtonAriaLabel:"Close dialpad",openDtmfDialpadLabel:"Show dialpad",dtmfDialpadPlaceholderText:"Enter number"};var en_US = {call:call$j,chat:chat$j,callWithChat:callWithChat$j};
18855
+ var call$j={cameraLabel:"Camera",noCamerasLabel:"No cameras found",cameraPermissionDenied:"Your browser is blocking access to your camera",cameraTurnedOff:"Your camera is turned off",chatButtonLabel:"Chat",close:"Close",complianceBannerNowOnlyRecording:"You are now only recording this meeting.",complianceBannerNowOnlyTranscription:"You are now only transcribing this meeting.",complianceBannerRecordingAndTranscriptionSaved:"Recording and transcription are being saved.",complianceBannerRecordingAndTranscriptionStarted:"Recording and transcription have started.",complianceBannerRecordingAndTranscriptionStopped:"Recording and transcription have stopped.",complianceBannerRecordingSaving:"Recording is being saved.",complianceBannerRecordingStarted:"Recording has started.",complianceBannerRecordingStopped:"Recording has stopped.",complianceBannerTranscriptionStarted:"Transcription has started.",complianceBannerTranscriptionConsent:"By joining, you are giving consent for this meeting to be transcribed.",complianceBannerTranscriptionSaving:"Transcription is being saved.",complianceBannerTranscriptionStopped:"Transcription has stopped.",configurationPageTitle:"Start a call",copyInviteLinkButtonLabel:"Copy invite link",copyInviteLinkActionedAriaLabel:"Invite link copied",defaultPlaceHolder:"Select an option",dismissSidePaneButtonLabel:"Close",videoEffectsPaneTitle:"Effects",videoEffectsPaneBackgroundSelectionTitle:"Background",configurationPageVideoEffectsButtonLabel:"Effects",unableToStartVideoEffect:"Unable to apply video effect.",blurBackgroundEffectButtonLabel:"Blur",blurBackgroundTooltip:"Blur Background",removeBackgroundEffectButtonLabel:"None",removeBackgroundTooltip:"Remove Background",cameraOffBackgroundEffectWarningText:"Your camera is off. Turn on camera to see video effect.",failedToJoinCallDueToNoNetworkMoreDetails:"Call was disconnected due to a network issue. Check your connection and join again.",failedToJoinCallDueToNoNetworkTitle:"Call disconnected",failedToJoinTeamsMeetingReasonAccessDeniedMoreDetails:"You were not granted entry in the call. If this was a mistake, re-join the call.",failedToJoinTeamsMeetingReasonAccessDeniedTitle:"Dismissed from lobby",learnMore:"Learn more",leavingCallTitle:"Leaving...",leftCallMoreDetails:"If this was a mistake, re-join the call.",leftCallTitle:"You left the call",lobbyScreenConnectingToCallTitle:"Joining call",lobbyScreenWaitingToBeAdmittedTitle:"Waiting to be admitted",microphonePermissionDenied:"Your browser is blocking access to your microphone",microphoneToggleInLobbyNotAllowed:"Cannot mute or unmute while in lobby.",mutedMessage:"You're muted",networkReconnectMoreDetails:"Looks like something went wrong. We're trying to get back into the call.",networkReconnectTitle:"Hold on",deniedPermissionToRoomDetails:"You do not have permission to join this room.",deniedPermissionToRoomTitle:"Permission denied to room",peopleButtonLabel:"People",peoplePaneTitle:"People",peopleButtonTooltipOpen:"Show participants",peopleButtonTooltipClose:"Hide participants",peoplePaneSubTitle:"In this call",privacyPolicy:"Privacy policy",rejoinCallButtonLabel:"Re-join call",removedFromCallMoreDetails:"Another participant removed you from the call.",removedFromCallTitle:"You were removed",removeMenuLabel:"Remove",returnToCallButtonAriaDescription:"Return to Call",returnToCallButtonAriaLabel:"Back",roomNotFoundDetails:"Room ID provided is not valid.",roomNotFoundTitle:"Room not found",soundLabel:"Sound",noMicrophonesLabel:"No microphones found",noSpeakersLabel:"No speakers found",startCallButtonLabel:"Start call",openDialpadButtonLabel:"Dial phone number",peoplePaneAddPeopleButtonLabel:"Add People",dialpadStartCallButtonLabel:"Call",dialpadModalTitle:"Dial Phone Number",dialpadModalAriaLabel:"Dialpad",dialpadCloseModalButtonAriaLabel:"Close dialpad",moreButtonCallingLabel:"More",resumeCallButtonLabel:"Resume",resumingCallButtonLabel:"Resuming...",resumeCallButtonAriaLabel:"Resume call",resumingCallButtonAriaLabel:"Resume call",holdScreenLabel:"You're on hold",openDtmfDialpadLabel:"Show dialpad",dtmfDialpadPlaceholderText:"Enter number",outboundCallingNoticeString:"Calling...",participantJoinedNoticeString:"{displayName} joined",twoParticipantJoinedNoticeString:"{displayName1} and {displayName2} have joined",threeParticipantJoinedNoticeString:"{displayName1}, {displayName2} and {displayName3} have joined",participantLeftNoticeString:"{displayName} left",twoParticipantLeftNoticeString:"{displayName1} and {displayName2} have left",threeParticipantLeftNoticeString:"{displayName1}, {displayName2} and {displayName3} have left",unnamedParticipantString:"unnamed participant",manyUnnamedParticipantsJoined:"unnamed participant and {numOfParticipants} other participants joined",manyUnnamedParticipantsLeft:"unnamed participant and {numOfParticipants} other participants left",manyParticipantsJoined:"{displayName1}, {displayName2}, {displayName3} and {numOfParticipants} other participants joined",manyParticipantsLeft:"{displayName1}, {displayName2}, {displayName3} and {numOfParticipants} other participants left",liveCaptionsLabel:"Live captions",captionsSettingsLabel:"Caption settings",startCaptionsButtonOnLabel:"Turn on captions",startCaptionsButtonOffLabel:"Turn off captions",startCaptionsButtonTooltipOnContent:"Turn off captions",startCaptionsButtonTooltipOffContent:"Turn on captions",captionsSettingsModalTitle:"What language is being spoken?",captionsSettingsDropdownLabel:"Spoken language",captionsSettingsDropdownInfoText:"Language that everyone on this call is speaking.",captionsSettingsConfirmButtonLabel:"Confirm",captionsSettingsCancelButtonLabel:"Cancel",captionsSettingsModalAriaLabel:"Captions Setting Modal",captionsSettingsCloseModalButtonAriaLabel:"Close Captions Setting",captionsBannerMoreButtonCallingLabel:"More",captionsBannerMoreButtonTooltip:"More options",captionsAvailableLanguageStrings:{"ar-ae":"Arabic - U.A.E.","ar-sa":"Arabic - Saudi Arabia","da-dk":"Danish","de-de":"German - Germany","en-au":"English - Australia","en-ca":"English - Canada","en-gb":"English - United Kingdom","en-in":"English - India","en-nz":"English - New Zealand","en-us":"English - United States","es-es":"Spanish - Spain (Modern Sort)","es-mx":"Spanish - Mexico","fi-fi":"Finnish","fr-ca":"French - Canada","fr-fr":"French - France","hi-in":"Hindi","it-it":"Italian - Italy","ja-jp":"Japanese","ko-kr":"Korean","nb-no":"Norwegian (Bokmål)","nl-be":"Dutch - Belgium","nl-nl":"Dutch - Netherlands","pl-pl":"Polish","pt-br":"Portuguese - Brazil","ru-ru":"Russian","sv-se":"Swedish","zh-cn":"Chinese - People's Republic of China","zh-hk":"Chinese - Hong Kong SAR","cs-cz":"Czech","pt-pt":"Portuguese - Portugal","tr-tr":"Turkish","vi-vn":"Vietnamese","th-th":"Thai","he-il":"Hebrew","cy-gb":"Welsh","uk-ua":"Ukrainian","el-gr":"Greek","hu-hu":"Hungarian","ro-ro":"Romanian","sk-sk":"Slovak","zh-tw":"Chinese - Taiwan"},captionsBannerSpinnerText:"Starting captions...",transferPageTransferorText:"Transferring...",transferPageTransferTargetText:"Connecting...",transferPageUnknownTransferorDisplayName:"Unknown",transferPageUnknownTransferTargetDisplayName:"Unknown",transferPageNoticeString:"You are being transferred"};var chat$j={chatListHeader:"In this chat",uploadFile:"Upload File"};var callWithChat$j={chatButtonLabel:"Chat",chatButtonNewMessageNotificationLabel:"New Message",chatButtonTooltipClosedWithMessageCount:"Show chat ({unreadMessagesCount} unread)",chatButtonTooltipClose:"Hide chat",chatButtonTooltipOpen:"Show chat",chatPaneTitle:"Chat",copyInviteLinkButtonLabel:"Copy invite link",copyInviteLinkActionedAriaLabel:"Invite link copied",dismissSidePaneButtonLabel:"Close",moreDrawerAudioDeviceMenuTitle:"Audio Device",moreDrawerButtonLabel:"More options",moreDrawerButtonTooltip:"More options",moreDrawerMicrophoneMenuTitle:"Microphone",moreDrawerSpeakerMenuTitle:"Speaker",moreDrawerCaptionsMenuTitle:"Live captions",moreDrawerSpokenLanguageMenuTitle:"Spoken language",peopleButtonLabel:"People",peopleButtonTooltipOpen:"Show participants",peopleButtonTooltipClose:"Hide participants",peoplePaneSubTitle:"In this call",peoplePaneTitle:"People",pictureInPictureTileAriaLabel:"Video Feeds. Click to return to call screen.",removeMenuLabel:"Remove",openDialpadButtonLabel:"Dial phone number",returnToCallButtonAriaDescription:"Return to Call",returnToCallButtonAriaLabel:"Back",peoplePaneAddPeopleButtonLabel:"Add People",dialpadStartCallButtonLabel:"Call",dialpadModalTitle:"Dial Phone Number",dialpadModalAriaLabel:"Dialpad",dialpadCloseModalButtonAriaLabel:"Close dialpad",openDtmfDialpadLabel:"Show dialpad",dtmfDialpadPlaceholderText:"Enter number"};var en_US = {call:call$j,chat:chat$j,callWithChat:callWithChat$j};
18790
18856
 
18791
18857
  var call$i={cameraLabel:"Camera",noCamerasLabel:"No cameras found",cameraPermissionDenied:"Your browser is blocking access to your camera",cameraTurnedOff:"Your camera is turned off",chatButtonLabel:"Chat",close:"Close",complianceBannerNowOnlyRecording:"You are now only recording this meeting.",complianceBannerNowOnlyTranscription:"You are now only transcribing this meeting.",complianceBannerRecordingAndTranscriptionSaved:"Recording and transcription are being saved.",complianceBannerRecordingAndTranscriptionStarted:"Recording and transcription have started.",complianceBannerRecordingAndTranscriptionStopped:"Recording and transcription have stopped.",complianceBannerRecordingSaving:"Recording is being saved.",complianceBannerRecordingStarted:"Recording has started.",complianceBannerRecordingStopped:"Recording has stopped.",complianceBannerTranscriptionStarted:"Transcription has started.",complianceBannerTranscriptionConsent:"By joining, you are giving consent for this meeting to be transcribed.",complianceBannerTranscriptionSaving:"Transcription is being saved.",complianceBannerTranscriptionStopped:"Transcription has stopped.",configurationPageTitle:"Start a call",copyInviteLinkButtonLabel:"Copy invite link",copyInviteLinkActionedAriaLabel:"Invite link copied",defaultPlaceHolder:"Select an option",dismissSidePaneButtonLabel:"Close",videoEffectsPaneTitle:"Effects",videoEffectsPaneBackgroundSelectionTitle:"Background",configurationPageVideoEffectsButtonLabel:"Effects",unableToStartVideoEffect:"Unable to apply video effect.",blurBackgroundEffectButtonLabel:"Blur",blurBackgroundTooltip:"Blur Background",removeBackgroundEffectButtonLabel:"None",removeBackgroundTooltip:"Remove Background",cameraOffBackgroundEffectWarningText:"Your camera is off. Turn on camera to see video effect.",failedToJoinCallDueToNoNetworkMoreDetails:"Call was disconnected due to a network issue. Check your connection and join again.",failedToJoinCallDueToNoNetworkTitle:"Call disconnected",failedToJoinTeamsMeetingReasonAccessDeniedMoreDetails:"You were not granted entry in the call. If this was a mistake, re-join the call.",failedToJoinTeamsMeetingReasonAccessDeniedTitle:"Dismissed from lobby",learnMore:"Learn more",leavingCallTitle:"Leaving...",leftCallMoreDetails:"If this was a mistake, re-join the call.",leftCallTitle:"You left the call",lobbyScreenConnectingToCallTitle:"Joining call",lobbyScreenWaitingToBeAdmittedTitle:"Waiting to be admitted",microphonePermissionDenied:"Your browser is blocking access to your microphone",microphoneToggleInLobbyNotAllowed:"Cannot mute or unmute while in lobby.",mutedMessage:"You're muted",networkReconnectMoreDetails:"Looks like something went wrong. We're trying to get back into the call.",networkReconnectTitle:"Hold on",deniedPermissionToRoomDetails:"You do not have permission to join this room.",deniedPermissionToRoomTitle:"Permission denied to room",peopleButtonLabel:"People",peoplePaneTitle:"People",peopleButtonTooltipOpen:"Show participants",peopleButtonTooltipClose:"Hide participants",peoplePaneSubTitle:"In this call",privacyPolicy:"Privacy policy",rejoinCallButtonLabel:"Re-join call",removedFromCallMoreDetails:"Another participant removed you from the call.",removedFromCallTitle:"You were removed",removeMenuLabel:"Remove",returnToCallButtonAriaDescription:"Return to Call",returnToCallButtonAriaLabel:"Back",roomNotFoundDetails:"Room ID provided is not valid.",roomNotFoundTitle:"Room not found",soundLabel:"Sound",noMicrophonesLabel:"No microphones found",noSpeakersLabel:"No speakers found",startCallButtonLabel:"Start call",openDialpadButtonLabel:"Dial phone number",peoplePaneAddPeopleButtonLabel:"Add People",dialpadStartCallButtonLabel:"Call",dialpadModalTitle:"Dial Phone Number",dialpadModalAriaLabel:"Dialpad",dialpadCloseModalButtonAriaLabel:"Close dialpad",moreButtonCallingLabel:"More",resumeCallButtonLabel:"Resume",resumingCallButtonLabel:"Resuming...",resumeCallButtonAriaLabel:"Resume call",resumingCallButtonAriaLabel:"Resume call",holdScreenLabel:"You're on hold",openDtmfDialpadLabel:"Show dialpad",dtmfDialpadPlaceholderText:"Enter number",outboundCallingNoticeString:"Calling...",participantJoinedNoticeString:"{displayName} joined",twoParticipantJoinedNoticeString:"{displayName1} and {displayName2} have joined",threeParticipantJoinedNoticeString:"{displayName1}, {displayName2} and {displayName3} have joined",participantLeftNoticeString:"{displayName} left",twoParticipantLeftNoticeString:"{displayName1} and {displayName2} have left",threeParticipantLeftNoticeString:"{displayName1}, {displayName2} and {displayName3} have left",unnamedParticipantString:"unnamed participant",manyUnnamedParticipantsJoined:"unnamed participant and {numOfParticipants} other participants joined",manyUnnamedParticipantsLeft:"unnamed participant and {numOfParticipants} other participants left",manyParticipantsJoined:"{displayName1}, {displayName2}, {displayName3} and {numOfParticipants} other participants joined",manyParticipantsLeft:"{displayName1}, {displayName2}, {displayName3} and {numOfParticipants} other participants left",liveCaptionsLabel:"Live captions",captionsSettingsLabel:"Caption settings",startCaptionsButtonOnLabel:"Turn on captions",startCaptionsButtonOffLabel:"Turn off captions",startCaptionsButtonTooltipOnContent:"Turn off captions",startCaptionsButtonTooltipOffContent:"Turn on captions",captionsSettingsModalTitle:"What language is being spoken?",captionsSettingsDropdownLabel:"Spoken language",captionsSettingsDropdownInfoText:"Language that everyone on this call is speaking.",captionsSettingsConfirmButtonLabel:"Confirm",captionsSettingsCancelButtonLabel:"Cancel",captionsSettingsModalAriaLabel:"Captions Setting Modal",captionsSettingsCloseModalButtonAriaLabel:"Close Captions Setting",captionsBannerMoreButtonCallingLabel:"More",captionsBannerMoreButtonTooltip:"More options",captionsAvailableLanguageStrings:{"ar-ae":"Arabic - U.A.E.","ar-sa":"Arabic - Saudi Arabia","da-dk":"Danish","de-de":"German - Germany","en-au":"English - Australia","en-ca":"English - Canada","en-gb":"English - United Kingdom","en-in":"English - India","en-nz":"English - New Zealand","en-us":"English - United States","es-es":"Spanish - Spain (Modern Sort)","es-mx":"Spanish - Mexico","fi-fi":"Finnish","fr-ca":"French - Canada","fr-fr":"French - France","hi-in":"Hindi","it-it":"Italian - Italy","ja-jp":"Japanese","ko-kr":"Korean","nb-no":"Norwegian (Bokmål)","nl-be":"Dutch - Belgium","nl-nl":"Dutch - Netherlands","pl-pl":"Polish","pt-br":"Portuguese - Brazil","ru-ru":"Russian","sv-se":"Swedish","zh-cn":"Chinese - People's Republic of China","zh-hk":"Chinese - Hong Kong SAR","cs-cz":"Czech","pt-pt":"Portuguese - Portugal","tr-tr":"Turkish","vi-vn":"Vietnamese","th-th":"Thai","he-il":"Hebrew","cy-gb":"Welsh","uk-ua":"Ukrainian","el-gr":"Greek","hu-hu":"Hungarian","ro-ro":"Romanian","sk-sk":"Slovak","zh-tw":"Chinese - Taiwan"},captionsBannerSpinnerText:"Starting captions...",transferPageTransferorText:"Transferring...",transferPageTransferTargetText:"Connecting...",transferPageUnknownTransferorDisplayName:"Unknown",transferPageUnknownTransferTargetDisplayName:"Unknown"};var chat$i={chatListHeader:"In this chat",uploadFile:"Upload File"};var callWithChat$i={chatButtonLabel:"Chat",chatButtonNewMessageNotificationLabel:"New Message",chatButtonTooltipClosedWithMessageCount:"Show chat ({unreadMessagesCount} unread)",chatButtonTooltipClose:"Hide chat",chatButtonTooltipOpen:"Show chat",chatPaneTitle:"Chat",copyInviteLinkButtonLabel:"Copy invite link",copyInviteLinkActionedAriaLabel:"Invite link copied",dismissSidePaneButtonLabel:"Close",moreDrawerAudioDeviceMenuTitle:"Audio Device",moreDrawerButtonLabel:"More options",moreDrawerButtonTooltip:"More options",moreDrawerMicrophoneMenuTitle:"Microphone",moreDrawerSpeakerMenuTitle:"Speaker",moreDrawerCaptionsMenuTitle:"Live captions",moreDrawerSpokenLanguageMenuTitle:"Spoken language",peopleButtonLabel:"People",peopleButtonTooltipOpen:"Show participants",peopleButtonTooltipClose:"Hide participants",peoplePaneSubTitle:"In this call",peoplePaneTitle:"People",pictureInPictureTileAriaLabel:"Video Feeds. Click to return to call screen.",removeMenuLabel:"Remove",openDialpadButtonLabel:"Dial phone number",returnToCallButtonAriaDescription:"Return to Call",returnToCallButtonAriaLabel:"Back",peoplePaneAddPeopleButtonLabel:"Add People",dialpadStartCallButtonLabel:"Call",dialpadModalTitle:"Dial Phone Number",dialpadModalAriaLabel:"Dialpad",dialpadCloseModalButtonAriaLabel:"Close dialpad",openDtmfDialpadLabel:"Show dialpad",dtmfDialpadPlaceholderText:"Enter number"};var en_GB = {call:call$i,chat:chat$i,callWithChat:callWithChat$i};
18792
18858
 
@@ -19252,22 +19318,6 @@ const convertObservableFileUploadToFileUploadsUiState = (fileUploads) => {
19252
19318
  }, {});
19253
19319
  };
19254
19320
 
19255
- // Copyright (c) Microsoft Corporation.
19256
- // Licensed under the MIT license.
19257
- /**
19258
- * Subset of CallCompositePages that represent an end call state.
19259
- * @private
19260
- */
19261
- const END_CALL_PAGES = [
19262
- 'accessDeniedTeamsMeeting',
19263
- 'joinCallFailedDueToNoNetwork',
19264
- 'leftCall',
19265
- /* @conditional-compile-remove(rooms) */ 'deniedPermissionToRoom',
19266
- 'removedFromCall',
19267
- /* @conditional-compile-remove(rooms) */ 'roomNotFound',
19268
- /* @conditional-compile-remove(unsupported-browser) */ 'unsupportedEnvironment'
19269
- ];
19270
-
19271
19321
  // Copyright (c) Microsoft Corporation.
19272
19322
  // Licensed under the MIT license.
19273
19323
  var __awaiter$i = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
@@ -19279,443 +19329,80 @@ var __awaiter$i = (window && window.__awaiter) || function (thisArg, _arguments,
19279
19329
  step((generator = generator.apply(thisArg, _arguments || [])).next());
19280
19330
  });
19281
19331
  };
19282
- const ACCESS_DENIED_TEAMS_MEETING_SUB_CODE = 5854;
19283
- const REMOTE_PSTN_USER_HUNG_UP = 560000;
19284
- const REMOVED_FROM_CALL_SUB_CODES = [5000, 5300, REMOTE_PSTN_USER_HUNG_UP];
19285
- /* @conditional-compile-remove(rooms) */
19286
- const ROOM_NOT_FOUND_SUB_CODE = 5751;
19287
- /* @conditional-compile-remove(rooms) */
19288
- const DENIED_PERMISSION_TO_ROOM_SUB_CODE = 5828;
19289
- /**
19290
- * @private
19291
- */
19292
- const isCameraOn = (state) => {
19293
- if (state.call) {
19294
- const stream = state.call.localVideoStreams.find((stream) => stream.mediaStreamType === 'Video');
19295
- return !!stream;
19296
- }
19297
- else {
19298
- if (state.devices.selectedCamera) {
19299
- const previewOn = _isPreviewOn(state.devices);
19300
- return previewOn;
19301
- }
19302
- }
19303
- return false;
19332
+ var __asyncValues = (window && window.__asyncValues) || function (o) {
19333
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
19334
+ var m = o[Symbol.asyncIterator], i;
19335
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
19336
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
19337
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
19304
19338
  };
19305
19339
  /**
19306
- * Reduce the set of call controls visible on mobile.
19307
- * For example do not show screenshare button.
19308
- *
19340
+ * Context of Chat, which is a centralized context for all state updates
19309
19341
  * @private
19310
19342
  */
19311
- const reduceCallControlsForMobile = (callControlOptions) => {
19312
- if (callControlOptions === false) {
19313
- return false;
19314
- }
19315
- // Ensure call controls a valid object.
19316
- const reduceCallControlOptions = callControlOptions === true ? {} : callControlOptions || {};
19317
- // Set to compressed mode when composite is optimized for mobile
19318
- reduceCallControlOptions.displayType = 'compact';
19319
- // Do not show screen share button when composite is optimized for mobile unless the developer
19320
- // has explicitly opted in.
19321
- if (reduceCallControlOptions.screenShareButton !== true) {
19322
- reduceCallControlOptions.screenShareButton = false;
19343
+ class ChatContext {
19344
+ constructor(clientState, threadId) {
19345
+ this.emitter = new EventEmitter__default['default']();
19346
+ const thread = clientState.threads[threadId];
19347
+ this.threadId = threadId;
19348
+ if (!thread) {
19349
+ throw 'Cannot find threadId, please initialize thread before use!';
19350
+ }
19351
+ this.state = {
19352
+ userId: clientState.userId,
19353
+ displayName: clientState.displayName,
19354
+ thread,
19355
+ latestErrors: clientState.latestErrors
19356
+ };
19323
19357
  }
19324
- return reduceCallControlOptions;
19325
- };
19326
- var CallEndReasons;
19327
- (function (CallEndReasons) {
19328
- CallEndReasons[CallEndReasons["LEFT_CALL"] = 0] = "LEFT_CALL";
19329
- CallEndReasons[CallEndReasons["ACCESS_DENIED"] = 1] = "ACCESS_DENIED";
19330
- CallEndReasons[CallEndReasons["REMOVED_FROM_CALL"] = 2] = "REMOVED_FROM_CALL";
19331
- CallEndReasons[CallEndReasons["ROOM_NOT_FOUND"] = 3] = "ROOM_NOT_FOUND";
19332
- CallEndReasons[CallEndReasons["DENIED_PERMISSION_TO_ROOM"] = 4] = "DENIED_PERMISSION_TO_ROOM";
19333
- })(CallEndReasons || (CallEndReasons = {}));
19334
- const getCallEndReason = (call) => {
19335
- var _a, _b, _c, _d, _e;
19336
- const remoteParticipantsEndedArray = Array.from(Object.values(call.remoteParticipantsEnded));
19337
- /**
19338
- * Handle the special case in a PSTN call where removing the last user kicks the caller out of the call.
19339
- * The code and subcode is the same as when a user is removed from a teams interop call.
19340
- * Hence, we look at the last remote participant removed to determine if the last participant removed was a phone number.
19341
- * If yes, the caller was kicked out of the call, but we need to show them that they left the call.
19342
- * 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.
19343
- */
19344
- if (remoteParticipantsEndedArray.length === 1 &&
19345
- communicationCommon.isPhoneNumberIdentifier(remoteParticipantsEndedArray[0].identifier) &&
19346
- ((_a = call.callEndReason) === null || _a === void 0 ? void 0 : _a.subCode) !== REMOTE_PSTN_USER_HUNG_UP) {
19347
- return CallEndReasons.LEFT_CALL;
19358
+ onStateChange(handler) {
19359
+ this.emitter.on('stateChanged', handler);
19348
19360
  }
19349
- if (((_b = call.callEndReason) === null || _b === void 0 ? void 0 : _b.subCode) && call.callEndReason.subCode === ACCESS_DENIED_TEAMS_MEETING_SUB_CODE) {
19350
- return CallEndReasons.ACCESS_DENIED;
19361
+ offStateChange(handler) {
19362
+ this.emitter.off('stateChanged', handler);
19351
19363
  }
19352
- if (((_c = call.callEndReason) === null || _c === void 0 ? void 0 : _c.subCode) && REMOVED_FROM_CALL_SUB_CODES.includes(call.callEndReason.subCode)) {
19353
- return CallEndReasons.REMOVED_FROM_CALL;
19364
+ setState(state) {
19365
+ this.state = state;
19366
+ this.emitter.emit('stateChanged', this.state);
19354
19367
  }
19355
- /* @conditional-compile-remove(rooms) */
19356
- if (((_d = call.callEndReason) === null || _d === void 0 ? void 0 : _d.subCode) && call.callEndReason.subCode === ROOM_NOT_FOUND_SUB_CODE) {
19357
- return CallEndReasons.ROOM_NOT_FOUND;
19368
+ getState() {
19369
+ return this.state;
19358
19370
  }
19359
- /* @conditional-compile-remove(rooms) */
19360
- if (((_e = call.callEndReason) === null || _e === void 0 ? void 0 : _e.subCode) && call.callEndReason.subCode === DENIED_PERMISSION_TO_ROOM_SUB_CODE) {
19361
- return CallEndReasons.DENIED_PERMISSION_TO_ROOM;
19371
+ setError(error) {
19372
+ this.setState(Object.assign(Object.assign({}, this.state), { error }));
19362
19373
  }
19363
- if (call.callEndReason) {
19364
- // No error codes match, assume the user simply left the call regularly
19365
- return CallEndReasons.LEFT_CALL;
19374
+ updateClientState(clientState) {
19375
+ const thread = clientState.threads[this.threadId];
19376
+ if (!thread) {
19377
+ throw 'Cannot find threadId, please make sure thread state is still in Stateful ChatClient.';
19378
+ }
19379
+ let updatedState = {
19380
+ userId: clientState.userId,
19381
+ displayName: clientState.displayName,
19382
+ thread,
19383
+ latestErrors: clientState.latestErrors
19384
+ };
19385
+ /* @conditional-compile-remove(file-sharing) */
19386
+ updatedState = Object.assign(Object.assign({}, updatedState), { fileUploads: this.state.fileUploads });
19387
+ this.setState(updatedState);
19366
19388
  }
19367
- throw new Error('No matching call end reason');
19368
- };
19389
+ }
19369
19390
  /**
19370
- * Get the current call composite page based on the current call composite state
19371
- *
19372
- * @param Call - The current call state
19373
- * @param previousCall - The state of the most recent previous call that has ended.
19374
- *
19375
- * @remarks - The previousCall state is needed to determine if the call has ended.
19376
- * When the call ends a new call object is created, and so we must lookback at the
19377
- * previous call state to understand how the call has ended. If there is no previous
19378
- * call we know that this is a fresh call and can display the configuration page.
19379
- *
19380
19391
  * @private
19381
19392
  */
19382
- const getCallCompositePage = (call, previousCall, unsupportedBrowserInfo, transferCall) => {
19383
- /* @conditional-compile-remove(unsupported-browser) */
19384
- if (isUnsupportedEnvironment(unsupportedBrowserInfo.environmentInfo, unsupportedBrowserInfo.unsupportedBrowserVersionOptedIn)) {
19385
- return 'unsupportedEnvironment';
19386
- }
19387
- /* @conditional-compile-remove(call-transfer) */
19388
- if (transferCall !== undefined) {
19389
- return 'transferring';
19390
- }
19391
- if (call) {
19392
- // Must check for ongoing call *before* looking at any previous calls.
19393
- // If the composite completes one call and joins another, the previous calls
19394
- // will be populated, but not relevant for determining the page.
19395
- // `_isInLobbyOrConnecting` needs to be checked first because `_isInCall` also returns true when call is in lobby.
19396
- if (_isInLobbyOrConnecting(call === null || call === void 0 ? void 0 : call.state)) {
19397
- return 'lobby';
19398
- // `LocalHold` needs to be checked before `isInCall` since it is also a state that's considered in call.
19399
- }
19400
- else if ((call === null || call === void 0 ? void 0 : call.state) === 'LocalHold') {
19401
- /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
19402
- return 'hold';
19403
- }
19404
- else if ((call === null || call === void 0 ? void 0 : call.state) === 'Disconnecting') {
19405
- return 'leaving';
19406
- }
19407
- else if (_isInCall(call === null || call === void 0 ? void 0 : call.state)) {
19408
- return 'call';
19409
- }
19410
- else {
19411
- // When the call object has been constructed after clicking , but before 'connecting' has been
19412
- // set on the call object, we continue to show the configuration screen.
19413
- // The call object does not correctly reflect local device state until `call.state` moves to `connecting`.
19414
- // Moving to the 'lobby' page too soon leads to components that depend on the `call` object to show incorrect
19415
- // transitional state.
19416
- return 'configuration';
19417
- }
19418
- }
19419
- if (previousCall) {
19420
- const reason = getCallEndReason(previousCall);
19421
- /* @conditional-compile-remove(rooms) */
19422
- switch (reason) {
19423
- case CallEndReasons.ROOM_NOT_FOUND:
19424
- return 'roomNotFound';
19425
- case CallEndReasons.DENIED_PERMISSION_TO_ROOM:
19426
- return 'deniedPermissionToRoom';
19427
- }
19428
- switch (reason) {
19429
- case CallEndReasons.ACCESS_DENIED:
19430
- return 'accessDeniedTeamsMeeting';
19431
- case CallEndReasons.REMOVED_FROM_CALL:
19432
- return 'removedFromCall';
19433
- case CallEndReasons.LEFT_CALL:
19434
- if (previousCall.diagnostics.network.latest.noNetwork) {
19435
- return 'joinCallFailedDueToNoNetwork';
19436
- }
19437
- return 'leftCall';
19438
- }
19439
- }
19440
- // No call state - show starting page (configuration)
19441
- return 'configuration';
19442
- };
19443
- /** @private */
19444
- const IsCallEndedPage = (
19445
- /**
19446
- * Explicitly listing the pages of this function intentionally.
19447
- * This protects against adding a new composite page that should be marked as an callEndedPage.
19448
- * EndCallPages are used to trigger onCallEnded events so this could easily be missed.
19449
- * When you add a new composite page this will throw a compiler error. If this new page is an
19450
- * EndCallPage ensure you update the END_CALL_PAGES. Afterwards update the `page` parameter
19451
- * type below to allow your new page, i.e. add `| <your new page>
19452
- */
19453
- page) => END_CALL_PAGES.includes(page);
19454
- /**
19455
- * Creates a new call control options object and sets the correct values for disabling
19456
- * the buttons provided in the `disabledControls` array.
19457
- * Returns a new object without changing the original object.
19458
- * @param callControlOptions options for the call control component that need to be modified.
19459
- * @param disabledControls An array of controls to disable.
19460
- * @returns a copy of callControlOptions with disabledControls disabled
19461
- * @private
19462
- */
19463
- const disableCallControls = (callControlOptions, disabledControls) => {
19464
- var _a;
19465
- if (callControlOptions === false) {
19466
- return false;
19467
- }
19468
- // Ensure we clone the prop if it is an object to ensure we do not mutate the original prop.
19469
- let newOptions = (_a = (callControlOptions instanceof Object ? Object.assign({}, callControlOptions) : callControlOptions)) !== null && _a !== void 0 ? _a : {};
19470
- if (newOptions === true || newOptions === undefined) {
19471
- newOptions = disabledControls.reduce((acc, key) => {
19472
- acc[key] = { disabled: true };
19473
- return acc;
19474
- }, {});
19475
- }
19476
- else {
19477
- disabledControls.forEach((key) => {
19478
- if (newOptions[key] !== false) {
19479
- newOptions[key] = { disabled: true };
19480
- }
19481
- });
19482
- }
19483
- return newOptions;
19484
- };
19485
- /**
19486
- * Check if a disabled object is provided for a button and returns if the button is disabled.
19487
- * A button is only disabled if is explicitly set to disabled.
19488
- *
19489
- * @param option
19490
- * @returns whether a button is disabled
19491
- * @private
19492
- */
19493
- const isDisabled$2 = (option) => {
19494
- if (option === undefined || typeof option === 'boolean') {
19495
- return false;
19496
- }
19497
- return option.disabled;
19498
- };
19499
- /* @conditional-compile-remove(call-readiness) */
19500
- /**
19501
- * @returns Permissions state for the camera.
19502
- */
19503
- const queryCameraPermissionFromPermissionsAPI = () => __awaiter$i(void 0, void 0, void 0, function* () {
19504
- try {
19505
- return (yield navigator.permissions.query({ name: 'camera' })).state;
19506
- }
19507
- catch (e) {
19508
- console.info('permissions API is not supported by browser', e);
19509
- return 'unsupported';
19510
- }
19511
- });
19512
- /* @conditional-compile-remove(call-readiness) */
19513
- /**
19514
- * @returns Permissions state for the microphone.
19515
- */
19516
- const queryMicrophonePermissionFromPermissionsAPI = () => __awaiter$i(void 0, void 0, void 0, function* () {
19517
- try {
19518
- return (yield navigator.permissions.query({ name: 'microphone' })).state;
19519
- }
19520
- catch (e) {
19521
- console.info('permissions API is not supported by browser', e);
19522
- return 'unsupported';
19523
- }
19524
- });
19525
- /* @conditional-compile-remove(call-readiness) */
19526
- /**
19527
- *
19528
- * This function uses permission API to determine if device permission state is granted, prompt or denied
19529
- * @returns whether device permission state is granted, prompt or denied
19530
- * If permission API is not supported on this browser, permission state is set to unsupported.
19531
- * @private
19532
- */
19533
- const getDevicePermissionState = (setVideoState, setAudioState) => __awaiter$i(void 0, void 0, void 0, function* () {
19534
- const [cameraResult, microphoneResult] = yield Promise.all([
19535
- queryCameraPermissionFromPermissionsAPI(),
19536
- queryMicrophonePermissionFromPermissionsAPI()
19537
- ]);
19538
- setVideoState(cameraResult);
19539
- setAudioState(microphoneResult);
19540
- });
19541
- /* @conditional-compile-remove(unsupported-browser) */
19542
- const isUnsupportedEnvironment = (environmentInfo, unsupportedBrowserVersionOptedIn) => {
19543
- return !!((environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowser) === false ||
19544
- ((environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowserVersion) === false && !unsupportedBrowserVersionOptedIn) ||
19545
- (environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedPlatform) === false);
19546
- };
19547
- /**
19548
- * Check if an object is identifier.
19549
- *
19550
- * @param identifier
19551
- * @returns whether an identifier is one of identifier types (for runtime validation)
19552
- * @private
19553
- */
19554
- const isValidIdentifier = (identifier) => {
19555
- return (communicationCommon.isCommunicationUserIdentifier(identifier) ||
19556
- communicationCommon.isPhoneNumberIdentifier(identifier) ||
19557
- communicationCommon.isMicrosoftTeamsUserIdentifier(identifier) ||
19558
- communicationCommon.isUnknownIdentifier(identifier));
19559
- };
19560
- /**
19561
- * Check if we are using safari browser
19562
- * @private
19563
- */
19564
- const _isSafari = (environmentInfo) => {
19565
- /* @conditional-compile-remove(unsupported-browser) */
19566
- return (environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.environment.browser) === 'safari';
19567
- };
19568
- /**
19569
- * @private
19570
- * This is the util function to create a participant modifier for remote participantList
19571
- * It memoize previous original participant items and only update the changed participant
19572
- * It takes in one modifier function to generate one single participant object, it returns undefined if the object keeps unmodified
19573
- */
19574
- const createParticipantModifier = (createModifiedParticipant) => {
19575
- let previousParticipantState = undefined;
19576
- let modifiedParticipants = {};
19577
- const memoizedParticipants = {};
19578
- return (state) => {
19579
- var _a, _b, _c, _d;
19580
- // if root state is the same, we don't need to update the participants
19581
- if (((_a = state.call) === null || _a === void 0 ? void 0 : _a.remoteParticipants) !== previousParticipantState) {
19582
- modifiedParticipants = {};
19583
- const originalParticipants = (_b = state.call) === null || _b === void 0 ? void 0 : _b.remoteParticipants;
19584
- for (const key in originalParticipants) {
19585
- const modifiedParticipant = createModifiedParticipant(key, originalParticipants[key]);
19586
- if (modifiedParticipant === undefined) {
19587
- modifiedParticipants[key] = originalParticipants[key];
19588
- continue;
19589
- }
19590
- // Generate the new item if original cached item has been changed
19591
- if (((_c = memoizedParticipants[key]) === null || _c === void 0 ? void 0 : _c.originalRef) !== originalParticipants[key]) {
19592
- memoizedParticipants[key] = {
19593
- newParticipant: modifiedParticipant,
19594
- originalRef: originalParticipants[key]
19595
- };
19596
- }
19597
- // the modified participant is always coming from the memoized cache, whether is was refreshed
19598
- // from the previous closure or not
19599
- modifiedParticipants[key] = memoizedParticipants[key].newParticipant;
19600
- }
19601
- previousParticipantState = (_d = state.call) === null || _d === void 0 ? void 0 : _d.remoteParticipants;
19602
- }
19603
- return Object.assign(Object.assign({}, state), { call: state.call
19604
- ? Object.assign(Object.assign({}, state.call), { remoteParticipants: modifiedParticipants }) : undefined });
19605
- };
19606
- };
19607
- /**
19608
- * @private
19609
- */
19610
- const dismissVideoEffectsError = (toDismiss) => {
19611
- var _a;
19612
- const now = new Date(Date.now());
19613
- const toDismissTimestamp = (_a = toDismiss.timestamp) !== null && _a !== void 0 ? _a : now;
19614
- // Record that this error was dismissed for the first time right now.
19615
- return {
19616
- dismissedAt: now > toDismissTimestamp ? now : toDismissTimestamp,
19617
- activeSince: toDismiss.timestamp
19618
- };
19619
- };
19620
- /* @conditional-compile-remove(video-background-effects) */
19621
- /** @private */
19622
- const getBackgroundEffectFromSelectedEffect = (selectedEffect) => (selectedEffect === null || selectedEffect === void 0 ? void 0 : selectedEffect.effectName) === 'blur'
19623
- ? new communicationCallingEffects.BackgroundBlurEffect()
19624
- : (selectedEffect === null || selectedEffect === void 0 ? void 0 : selectedEffect.effectName) === 'replacement'
19625
- ? new communicationCallingEffects.BackgroundReplacementEffect({ backgroundImageUrl: selectedEffect.backgroundImageUrl })
19626
- : undefined;
19627
- /* @conditional-compile-remove(video-background-effects) */
19628
- /**
19629
- * @remarks this logic should mimic the onToggleCamera in the common call handlers.
19630
- * @private
19631
- */
19632
- const getSelectedCameraFromAdapterState = (state) => state.devices.selectedCamera || state.devices.cameras[0];
19633
-
19634
- // Copyright (c) Microsoft Corporation.
19635
- // Licensed under the MIT license.
19636
- var __awaiter$h = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
19637
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19638
- return new (P || (P = Promise))(function (resolve, reject) {
19639
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
19640
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19641
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19642
- step((generator = generator.apply(thisArg, _arguments || [])).next());
19643
- });
19644
- };
19645
- var __asyncValues = (window && window.__asyncValues) || function (o) {
19646
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
19647
- var m = o[Symbol.asyncIterator], i;
19648
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
19649
- function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
19650
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
19651
- };
19652
- /**
19653
- * Context of Chat, which is a centralized context for all state updates
19654
- * @private
19655
- */
19656
- class ChatContext {
19657
- constructor(clientState, threadId) {
19658
- this.emitter = new EventEmitter__default['default']();
19659
- const thread = clientState.threads[threadId];
19660
- this.threadId = threadId;
19661
- if (!thread) {
19662
- throw 'Cannot find threadId, please initialize thread before use!';
19663
- }
19664
- this.state = {
19665
- userId: clientState.userId,
19666
- displayName: clientState.displayName,
19667
- thread,
19668
- latestErrors: clientState.latestErrors
19669
- };
19670
- }
19671
- onStateChange(handler) {
19672
- this.emitter.on('stateChanged', handler);
19673
- }
19674
- offStateChange(handler) {
19675
- this.emitter.off('stateChanged', handler);
19676
- }
19677
- setState(state) {
19678
- this.state = state;
19679
- this.emitter.emit('stateChanged', this.state);
19680
- }
19681
- getState() {
19682
- return this.state;
19683
- }
19684
- setError(error) {
19685
- this.setState(Object.assign(Object.assign({}, this.state), { error }));
19686
- }
19687
- updateClientState(clientState) {
19688
- const thread = clientState.threads[this.threadId];
19689
- if (!thread) {
19690
- throw 'Cannot find threadId, please make sure thread state is still in Stateful ChatClient.';
19691
- }
19692
- let updatedState = {
19693
- userId: clientState.userId,
19694
- displayName: clientState.displayName,
19695
- thread,
19696
- latestErrors: clientState.latestErrors
19697
- };
19698
- /* @conditional-compile-remove(file-sharing) */
19699
- updatedState = Object.assign(Object.assign({}, updatedState), { fileUploads: this.state.fileUploads });
19700
- this.setState(updatedState);
19701
- }
19702
- }
19703
- /**
19704
- * @private
19705
- */
19706
- class AzureCommunicationChatAdapter {
19707
- constructor(chatClient, chatThreadClient,
19708
- /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */ options) {
19709
- /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
19710
- this.credential = undefined;
19711
- this.emitter = new EventEmitter__default['default']();
19712
- this.bindAllPublicMethods();
19713
- this.chatClient = chatClient;
19714
- this.chatThreadClient = chatThreadClient;
19715
- this.context = new ChatContext(chatClient.getState(), chatThreadClient.threadId);
19716
- /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
19717
- if (options && options.credential) {
19718
- this.credential = options.credential;
19393
+ class AzureCommunicationChatAdapter {
19394
+ constructor(chatClient, chatThreadClient,
19395
+ /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */ options) {
19396
+ /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
19397
+ this.credential = undefined;
19398
+ this.emitter = new EventEmitter__default['default']();
19399
+ this.bindAllPublicMethods();
19400
+ this.chatClient = chatClient;
19401
+ this.chatThreadClient = chatThreadClient;
19402
+ this.context = new ChatContext(chatClient.getState(), chatThreadClient.threadId);
19403
+ /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
19404
+ if (options && options.credential) {
19405
+ this.credential = options.credential;
19719
19406
  }
19720
19407
  /* @conditional-compile-remove(file-sharing) */ /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
19721
19408
  this.fileUploadAdapter = new AzureCommunicationFileUploadAdapter(this.context);
@@ -19768,9 +19455,9 @@ class AzureCommunicationChatAdapter {
19768
19455
  this.unsubscribeAllEvents();
19769
19456
  }
19770
19457
  fetchInitialData() {
19771
- return __awaiter$h(this, void 0, void 0, function* () {
19458
+ return __awaiter$i(this, void 0, void 0, function* () {
19772
19459
  // If get properties fails we dont want to try to get the participants after.
19773
- yield this.asyncTeeErrorToEventEmitter(() => __awaiter$h(this, void 0, void 0, function* () {
19460
+ yield this.asyncTeeErrorToEventEmitter(() => __awaiter$i(this, void 0, void 0, function* () {
19774
19461
  var e_1, _a;
19775
19462
  yield this.chatThreadClient.getProperties();
19776
19463
  try {
@@ -19804,8 +19491,8 @@ class AzureCommunicationChatAdapter {
19804
19491
  this.context.offStateChange(handler);
19805
19492
  }
19806
19493
  sendMessage(content, options = {}) {
19807
- return __awaiter$h(this, void 0, void 0, function* () {
19808
- yield this.asyncTeeErrorToEventEmitter(() => __awaiter$h(this, void 0, void 0, function* () {
19494
+ return __awaiter$i(this, void 0, void 0, function* () {
19495
+ yield this.asyncTeeErrorToEventEmitter(() => __awaiter$i(this, void 0, void 0, function* () {
19809
19496
  /* @conditional-compile-remove(file-sharing) */
19810
19497
  options.metadata = Object.assign(Object.assign({}, options.metadata), convertFileUploadsUiStateToMessageMetadata(this.context.getState().fileUploads));
19811
19498
  /* @conditional-compile-remove(file-sharing) */
@@ -19822,51 +19509,51 @@ class AzureCommunicationChatAdapter {
19822
19509
  });
19823
19510
  }
19824
19511
  sendReadReceipt(chatMessageId) {
19825
- return __awaiter$h(this, void 0, void 0, function* () {
19826
- yield this.asyncTeeErrorToEventEmitter(() => __awaiter$h(this, void 0, void 0, function* () {
19512
+ return __awaiter$i(this, void 0, void 0, function* () {
19513
+ yield this.asyncTeeErrorToEventEmitter(() => __awaiter$i(this, void 0, void 0, function* () {
19827
19514
  yield this.handlers.onMessageSeen(chatMessageId);
19828
19515
  }));
19829
19516
  });
19830
19517
  }
19831
19518
  sendTypingIndicator() {
19832
- return __awaiter$h(this, void 0, void 0, function* () {
19833
- yield this.asyncTeeErrorToEventEmitter(() => __awaiter$h(this, void 0, void 0, function* () {
19519
+ return __awaiter$i(this, void 0, void 0, function* () {
19520
+ yield this.asyncTeeErrorToEventEmitter(() => __awaiter$i(this, void 0, void 0, function* () {
19834
19521
  yield this.handlers.onTyping();
19835
19522
  }));
19836
19523
  });
19837
19524
  }
19838
19525
  removeParticipant(userId) {
19839
- return __awaiter$h(this, void 0, void 0, function* () {
19840
- yield this.asyncTeeErrorToEventEmitter(() => __awaiter$h(this, void 0, void 0, function* () {
19526
+ return __awaiter$i(this, void 0, void 0, function* () {
19527
+ yield this.asyncTeeErrorToEventEmitter(() => __awaiter$i(this, void 0, void 0, function* () {
19841
19528
  yield this.handlers.onRemoveParticipant(userId);
19842
19529
  }));
19843
19530
  });
19844
19531
  }
19845
19532
  setTopic(topicName) {
19846
- return __awaiter$h(this, void 0, void 0, function* () {
19847
- yield this.asyncTeeErrorToEventEmitter(() => __awaiter$h(this, void 0, void 0, function* () {
19533
+ return __awaiter$i(this, void 0, void 0, function* () {
19534
+ yield this.asyncTeeErrorToEventEmitter(() => __awaiter$i(this, void 0, void 0, function* () {
19848
19535
  yield this.handlers.updateThreadTopicName(topicName);
19849
19536
  }));
19850
19537
  });
19851
19538
  }
19852
19539
  loadPreviousChatMessages(messagesToLoad) {
19853
- return __awaiter$h(this, void 0, void 0, function* () {
19854
- return yield this.asyncTeeErrorToEventEmitter(() => __awaiter$h(this, void 0, void 0, function* () {
19540
+ return __awaiter$i(this, void 0, void 0, function* () {
19541
+ return yield this.asyncTeeErrorToEventEmitter(() => __awaiter$i(this, void 0, void 0, function* () {
19855
19542
  return yield this.handlers.onLoadPreviousChatMessages(messagesToLoad);
19856
19543
  }));
19857
19544
  });
19858
19545
  }
19859
19546
  updateMessage(messageId, content, metadata, options) {
19860
- return __awaiter$h(this, void 0, void 0, function* () {
19861
- return yield this.asyncTeeErrorToEventEmitter(() => __awaiter$h(this, void 0, void 0, function* () {
19547
+ return __awaiter$i(this, void 0, void 0, function* () {
19548
+ return yield this.asyncTeeErrorToEventEmitter(() => __awaiter$i(this, void 0, void 0, function* () {
19862
19549
  /* @conditional-compile-remove(file-sharing) */
19863
19550
  return yield this.handlers.onUpdateMessage(messageId, content, metadata, options);
19864
19551
  }));
19865
19552
  });
19866
19553
  }
19867
19554
  deleteMessage(messageId) {
19868
- return __awaiter$h(this, void 0, void 0, function* () {
19869
- return yield this.asyncTeeErrorToEventEmitter(() => __awaiter$h(this, void 0, void 0, function* () {
19555
+ return __awaiter$i(this, void 0, void 0, function* () {
19556
+ return yield this.asyncTeeErrorToEventEmitter(() => __awaiter$i(this, void 0, void 0, function* () {
19870
19557
  return yield this.handlers.onDeleteMessage(messageId);
19871
19558
  }));
19872
19559
  });
@@ -19901,8 +19588,8 @@ class AzureCommunicationChatAdapter {
19901
19588
  }
19902
19589
  /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
19903
19590
  downloadAttachments(options) {
19904
- return __awaiter$h(this, void 0, void 0, function* () {
19905
- return this.asyncTeeErrorToEventEmitter(() => __awaiter$h(this, void 0, void 0, function* () {
19591
+ return __awaiter$i(this, void 0, void 0, function* () {
19592
+ return this.asyncTeeErrorToEventEmitter(() => __awaiter$i(this, void 0, void 0, function* () {
19906
19593
  if (this.credential === undefined) {
19907
19594
  const e = new Error();
19908
19595
  e['target'] = 'ChatThreadClient.getMessage';
@@ -19922,9 +19609,9 @@ class AzureCommunicationChatAdapter {
19922
19609
  }
19923
19610
  /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
19924
19611
  downloadAuthenticatedFile(accessToken, options) {
19925
- return __awaiter$h(this, void 0, void 0, function* () {
19612
+ return __awaiter$i(this, void 0, void 0, function* () {
19926
19613
  function fetchWithAuthentication(url, token) {
19927
- return __awaiter$h(this, void 0, void 0, function* () {
19614
+ return __awaiter$i(this, void 0, void 0, function* () {
19928
19615
  const headers = new Headers();
19929
19616
  headers.append('Authorization', `Bearer ${token}`);
19930
19617
  try {
@@ -19996,7 +19683,7 @@ class AzureCommunicationChatAdapter {
19996
19683
  this.emitter.off(event, listener);
19997
19684
  }
19998
19685
  asyncTeeErrorToEventEmitter(f) {
19999
- return __awaiter$h(this, void 0, void 0, function* () {
19686
+ return __awaiter$i(this, void 0, void 0, function* () {
20000
19687
  try {
20001
19688
  return yield f();
20002
19689
  }
@@ -20038,8 +19725,8 @@ const convertEventType = (type) => {
20038
19725
  *
20039
19726
  * @public
20040
19727
  */
20041
- const createAzureCommunicationChatAdapter = ({ endpoint: endpointUrl, userId, displayName, credential, threadId }) => __awaiter$h(void 0, void 0, void 0, function* () {
20042
- if (!isValidIdentifier(userId)) {
19728
+ const createAzureCommunicationChatAdapter = ({ endpoint: endpointUrl, userId, displayName, credential, threadId }) => __awaiter$i(void 0, void 0, void 0, function* () {
19729
+ if (!_isValidIdentifier(userId)) {
20043
19730
  throw new Error('Provided userId is invalid. Please provide valid identifier object.');
20044
19731
  }
20045
19732
  const chatClient = createStatefulChatClient({
@@ -20107,7 +19794,7 @@ beforeDispose) => {
20107
19794
  if (!credential || !displayName || !endpoint || !threadId || !userId) {
20108
19795
  return;
20109
19796
  }
20110
- (() => __awaiter$h(void 0, void 0, void 0, function* () {
19797
+ (() => __awaiter$i(void 0, void 0, void 0, function* () {
20111
19798
  if (adapterRef.current) {
20112
19799
  // Dispose the old adapter when a new one is created.
20113
19800
  //
@@ -20139,7 +19826,7 @@ beforeDispose) => {
20139
19826
  // Dispose any existing adapter when the component unmounts.
20140
19827
  React.useEffect(() => {
20141
19828
  return () => {
20142
- (() => __awaiter$h(void 0, void 0, void 0, function* () {
19829
+ (() => __awaiter$i(void 0, void 0, void 0, function* () {
20143
19830
  if (adapterRef.current) {
20144
19831
  if (beforeDisposeRef.current) {
20145
19832
  yield beforeDisposeRef.current(adapterRef.current);
@@ -20163,7 +19850,7 @@ beforeDispose) => {
20163
19850
  function createAzureCommunicationChatAdapterFromClient(chatClient, chatThreadClient,
20164
19851
  /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
20165
19852
  options) {
20166
- return __awaiter$h(this, void 0, void 0, function* () {
19853
+ return __awaiter$i(this, void 0, void 0, function* () {
20167
19854
  return new AzureCommunicationChatAdapter(chatClient, chatThreadClient,
20168
19855
  /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */ options);
20169
19856
  });
@@ -20376,7 +20063,7 @@ const sendboxContainerStyles = {
20376
20063
 
20377
20064
  // Copyright (c) Microsoft Corporation.
20378
20065
  // Licensed under the MIT license.
20379
- var __awaiter$g = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
20066
+ var __awaiter$h = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
20380
20067
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
20381
20068
  return new (P || (P = Promise))(function (resolve, reject) {
20382
20069
  function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
@@ -20397,7 +20084,7 @@ const AvatarPersona = (props) => {
20397
20084
  const { userId, dataProvider, text, imageUrl, imageInitials, initialsColor, initialsTextColor, showOverflowTooltip } = props;
20398
20085
  const [data, setData] = React.useState();
20399
20086
  React.useEffect(() => {
20400
- (() => __awaiter$g(void 0, void 0, void 0, function* () {
20087
+ (() => __awaiter$h(void 0, void 0, void 0, function* () {
20401
20088
  if (dataProvider && userId) {
20402
20089
  const newData = yield dataProvider(userId);
20403
20090
  if (avatarDeepDifferenceCheck(data, newData)) {
@@ -20764,6 +20451,253 @@ const FileDownloadErrorBar = (props) => {
20764
20451
  }
20765
20452
  };
20766
20453
 
20454
+ // Copyright (c) Microsoft Corporation.
20455
+ // Licensed under the MIT license.
20456
+ var __awaiter$g = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
20457
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
20458
+ return new (P || (P = Promise))(function (resolve, reject) {
20459
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20460
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
20461
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
20462
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20463
+ });
20464
+ };
20465
+ /**
20466
+ * @private
20467
+ */
20468
+ const ChatScreen = (props) => {
20469
+ const { onFetchAvatarPersonaData, onRenderMessage, onRenderTypingIndicator, options, styles, fileSharing, formFactor } = props;
20470
+ const defaultNumberOfChatMessagesToReload = 5;
20471
+ /* @conditional-compile-remove(file-sharing) */
20472
+ const [downloadErrorMessage, setDownloadErrorMessage] = React__default['default'].useState('');
20473
+ const adapter = useAdapter$1();
20474
+ const theme = useTheme();
20475
+ React.useEffect(() => {
20476
+ // Initial data should be always fetched by the composite(or external caller) instead of the adapter
20477
+ const fetchData = () => __awaiter$g(void 0, void 0, void 0, function* () {
20478
+ // Fetch initial data for adapter
20479
+ yield adapter.fetchInitialData();
20480
+ // Fetch initial set of messages. Without fetching messages here, if the Composite's adapter is changed the message thread does not load new messages.
20481
+ yield adapter.loadPreviousChatMessages(defaultNumberOfChatMessagesToReload);
20482
+ });
20483
+ fetchData();
20484
+ }, [adapter]);
20485
+ const messageThreadProps = usePropsFor$2(MessageThread);
20486
+ const sendBoxProps = usePropsFor$2(SendBox);
20487
+ const typingIndicatorProps = usePropsFor$2(TypingIndicator);
20488
+ const headerProps = useAdaptedSelector$1(getHeaderProps);
20489
+ const errorBarProps = usePropsFor$2(ErrorBar);
20490
+ const onRenderAvatarCallback = React.useCallback((userId, defaultOptions) => {
20491
+ return (React__default['default'].createElement(AvatarPersona, Object.assign({ userId: userId, hidePersonaDetails: true }, defaultOptions, { dataProvider: onFetchAvatarPersonaData })));
20492
+ }, [onFetchAvatarPersonaData]);
20493
+ const messageThreadStyles = Object.assign({}, messageThreadChatCompositeStyles(theme.semanticColors.bodyBackground), styles === null || styles === void 0 ? void 0 : styles.messageThread);
20494
+ const typingIndicatorStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.typingIndicator);
20495
+ const sendBoxStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.sendBox);
20496
+ const userId = toFlatCommunicationIdentifier(adapter.getState().userId);
20497
+ const fileUploadButtonOnChange = React.useCallback((files) => {
20498
+ if (!files) {
20499
+ return;
20500
+ }
20501
+ /* @conditional-compile-remove(file-sharing) */
20502
+ const fileUploads = adapter.registerActiveFileUploads(Array.from(files));
20503
+ /* @conditional-compile-remove(file-sharing) */
20504
+ fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler(userId, fileUploads);
20505
+ }, [adapter, fileSharing, userId]);
20506
+ /* @conditional-compile-remove(file-sharing) */
20507
+ 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) => {
20508
+ setDownloadErrorMessage(errorMessage);
20509
+ } })), [fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.downloadHandler]);
20510
+ /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
20511
+ const onRenderInlineAttachment = React.useCallback((attachment) => __awaiter$g(void 0, void 0, void 0, function* () {
20512
+ if (attachment.previewUrl) {
20513
+ const blob = yield adapter.downloadAttachments({ attachmentUrls: [attachment.previewUrl] });
20514
+ return blob;
20515
+ }
20516
+ return [{ blobUrl: '' }];
20517
+ }), [adapter]);
20518
+ const AttachFileButton = React.useCallback(() => {
20519
+ if (!(fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler)) {
20520
+ return null;
20521
+ }
20522
+ 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 }));
20523
+ }, [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]);
20524
+ return (React__default['default'].createElement(react.Stack, { className: chatContainer, grow: true },
20525
+ (options === null || options === void 0 ? void 0 : options.topic) !== false && React__default['default'].createElement(ChatHeader, Object.assign({}, headerProps)),
20526
+ React__default['default'].createElement(react.Stack, { className: chatArea, tokens: participantListContainerPadding, horizontal: true, grow: true },
20527
+ React__default['default'].createElement(react.Stack, { className: chatWrapper, grow: true },
20528
+ (options === null || options === void 0 ? void 0 : options.errorBar) !== false && React__default['default'].createElement(ErrorBar, Object.assign({}, errorBarProps)),
20529
+ /* @conditional-compile-remove(file-sharing) */
20530
+ React__default['default'].createElement(FileDownloadErrorBar, { onDismissDownloadErrorMessage: React.useCallback(() => {
20531
+ setDownloadErrorMessage('');
20532
+ }, []), fileDownloadErrorMessage: downloadErrorMessage || '' }),
20533
+ React__default['default'].createElement(MessageThread, Object.assign({}, messageThreadProps, { onRenderAvatar: onRenderAvatarCallback, onRenderMessage: onRenderMessage,
20534
+ /* @conditional-compile-remove(file-sharing) */
20535
+ onRenderFileDownloads: onRenderFileDownloads,
20536
+ /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
20537
+ onFetchAttachments: onRenderInlineAttachment, numberOfChatMessagesToReload: defaultNumberOfChatMessagesToReload, styles: messageThreadStyles })),
20538
+ React__default['default'].createElement(react.Stack, { className: react.mergeStyles(sendboxContainerStyles) },
20539
+ React__default['default'].createElement("div", { className: react.mergeStyles(typingIndicatorContainerStyles) }, onRenderTypingIndicator ? (onRenderTypingIndicator(typingIndicatorProps.typingUsers)) : (React__default['default'].createElement(TypingIndicator, Object.assign({}, typingIndicatorProps, { styles: typingIndicatorStyles })))),
20540
+ React__default['default'].createElement(react.Stack, { horizontal: formFactor === 'mobile' },
20541
+ formFactor === 'mobile' && (React__default['default'].createElement(react.Stack, { verticalAlign: "center" },
20542
+ React__default['default'].createElement(AttachFileButton, null))),
20543
+ React__default['default'].createElement(react.Stack, { grow: true },
20544
+ React__default['default'].createElement(SendBox, Object.assign({}, sendBoxProps, { autoFocus: options === null || options === void 0 ? void 0 : options.autoFocus, styles: sendBoxStyles,
20545
+ /* @conditional-compile-remove(file-sharing) */
20546
+ activeFileUploads: useSelector$2(fileUploadsSelector).files,
20547
+ /* @conditional-compile-remove(file-sharing) */
20548
+ onCancelFileUpload: adapter.cancelFileUpload }))),
20549
+ formFactor !== 'mobile' && React__default['default'].createElement(AttachFileButton, null)))),
20550
+ /* @conditional-compile-remove(chat-composite-participant-pane) */
20551
+ (options === null || options === void 0 ? void 0 : options.participantPane) === true && (React__default['default'].createElement(ChatScreenPeoplePane, { onFetchAvatarPersonaData: onFetchAvatarPersonaData, onFetchParticipantMenuItems: props.onFetchParticipantMenuItems, isMobile: formFactor === 'mobile' })))));
20552
+ };
20553
+
20554
+ // Copyright (c) Microsoft Corporation.
20555
+ /**
20556
+ * A customizable UI composite for the chat experience.
20557
+ *
20558
+ * @remarks Chat composite min width and height are respectively 17.5rem and 20rem (280px and 320px, with default rem at 16px)
20559
+ *
20560
+ * @public
20561
+ */
20562
+ const ChatComposite = (props) => {
20563
+ const { adapter, options, onFetchAvatarPersonaData, onRenderTypingIndicator, onRenderMessage, onFetchParticipantMenuItems } = props;
20564
+ const formFactor = props['formFactor'] || 'desktop';
20565
+ /**
20566
+ * @TODO Remove this function and pass the props directly when file-sharing is promoted to stable.
20567
+ * @private
20568
+ */
20569
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
20570
+ const fileSharingOptions = () => {
20571
+ /* @conditional-compile-remove(file-sharing) */
20572
+ return {
20573
+ fileSharing: options === null || options === void 0 ? void 0 : options.fileSharing
20574
+ };
20575
+ };
20576
+ return (React__default['default'].createElement("div", { className: chatScreenContainerStyle },
20577
+ React__default['default'].createElement(BaseProvider, Object.assign({}, props),
20578
+ React__default['default'].createElement(ChatAdapterProvider, { adapter: adapter },
20579
+ React__default['default'].createElement(ChatScreen, Object.assign({ formFactor: formFactor, options: options, onFetchAvatarPersonaData: onFetchAvatarPersonaData, onRenderTypingIndicator: onRenderTypingIndicator, onRenderMessage: onRenderMessage, onFetchParticipantMenuItems: onFetchParticipantMenuItems }, fileSharingOptions()))))));
20580
+ };
20581
+
20582
+ // Copyright (c) Microsoft Corporation.
20583
+ const CallAdapterContext = React.createContext(undefined);
20584
+ /**
20585
+ * @private
20586
+ */
20587
+ const CallAdapterProvider = (props) => {
20588
+ const { adapter } = props;
20589
+ return React__default['default'].createElement(CallAdapterContext.Provider, { value: adapter }, props.children);
20590
+ };
20591
+ /**
20592
+ * @private
20593
+ */
20594
+ const useAdapter = () => {
20595
+ const adapter = React.useContext(CallAdapterContext);
20596
+ if (!adapter) {
20597
+ throw 'Cannot find adapter please initialize before usage.';
20598
+ }
20599
+ return adapter;
20600
+ };
20601
+
20602
+ // Copyright (c) Microsoft Corporation.
20603
+ /**
20604
+ * @private
20605
+ */
20606
+ const useAdaptedSelector = (selector, selectorProps) => {
20607
+ return useSelectorWithAdaptation(selector, adaptCompositeState, selectorProps);
20608
+ };
20609
+ /**
20610
+ * @private
20611
+ */
20612
+ const useSelectorWithAdaptation = (selector, adaptState, selectorProps) => {
20613
+ var _a;
20614
+ const adapter = useAdapter();
20615
+ // Keeps track of whether the current component is mounted or not. If it has unmounted, make sure we do not modify the
20616
+ // state or it will cause React warnings in the console. https://skype.visualstudio.com/SPOOL/_workitems/edit/2453212
20617
+ const mounted = React.useRef(false);
20618
+ React.useEffect(() => {
20619
+ mounted.current = true;
20620
+ return () => {
20621
+ mounted.current = false;
20622
+ };
20623
+ });
20624
+ const callId = (_a = adapter.getState().call) === null || _a === void 0 ? void 0 : _a.id;
20625
+ const callConfigProps = React.useMemo(() => ({
20626
+ callId
20627
+ }), [callId]);
20628
+ const [props, setProps] = React.useState(selector(adaptState(adapter.getState()), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps));
20629
+ const propRef = React.useRef(props);
20630
+ propRef.current = props;
20631
+ React.useEffect(() => {
20632
+ const onStateChange = (state) => {
20633
+ if (!mounted.current) {
20634
+ return;
20635
+ }
20636
+ const newProps = selector(adaptState(state), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps);
20637
+ if (propRef.current !== newProps) {
20638
+ setProps(newProps);
20639
+ }
20640
+ };
20641
+ adapter.onStateChange(onStateChange);
20642
+ return () => {
20643
+ adapter.offStateChange(onStateChange);
20644
+ };
20645
+ }, [adaptState, adapter, selector, selectorProps, callConfigProps]);
20646
+ return props;
20647
+ };
20648
+ const memoizeState = memoizeOne__default['default']((userId, deviceManager, calls, latestErrors, displayName, alternateCallerId, environmentInfo) => ({
20649
+ userId,
20650
+ incomingCalls: {},
20651
+ incomingCallsEnded: {},
20652
+ callsEnded: {},
20653
+ deviceManager,
20654
+ callAgent: { displayName },
20655
+ calls,
20656
+ latestErrors,
20657
+ /* @conditional-compile-remove(PSTN-calls) */
20658
+ alternateCallerId,
20659
+ /* @conditional-compile-remove(unsupported-browser) */
20660
+ environmentInfo
20661
+ }));
20662
+ const memoizeCalls = memoizeOne__default['default']((call) => (call ? { [call.id]: call } : {}));
20663
+ const adaptCompositeState = (compositeState) => {
20664
+ return memoizeState(compositeState.userId, compositeState.devices, memoizeCalls(compositeState.call),
20665
+ // This is an unsafe type expansion.
20666
+ // compositeState.latestErrors can contain properties that are not valid in CallErrors.
20667
+ //
20668
+ // But there is no way to check for valid property names at runtime:
20669
+ // - The set of valid property names is built from types in the @azure/communication-calling.
20670
+ // Thus we don't have a literal array of allowed strings at runtime.
20671
+ // - Due to minification / uglification, the property names from the objects at runtime can't be used
20672
+ // to compare against permissible values inferred from the types.
20673
+ //
20674
+ // This is not a huge problem -- it simply means that our adapted selector will include some extra operations
20675
+ // that are unknown to the UI component and data binding libraries. Generic handling of the errors (e.g.,
20676
+ // just displaying them in some UI surface) will continue to work for these operations. Handling of
20677
+ // specific operations (e.g., acting on errors related to permission issues) will ignore these operations.
20678
+ compositeState.latestErrors, compositeState.displayName,
20679
+ /* @conditional-compile-remove(PSTN-calls) */
20680
+ compositeState.alternateCallerId,
20681
+ /* @conditional-compile-remove(unsupported-browser) */
20682
+ compositeState.environmentInfo);
20683
+ };
20684
+
20685
+ // Copyright (c) Microsoft Corporation.
20686
+ // Licensed under the MIT license.
20687
+ /**
20688
+ * Subset of CallCompositePages that represent an end call state.
20689
+ * @private
20690
+ */
20691
+ const END_CALL_PAGES = [
20692
+ 'accessDeniedTeamsMeeting',
20693
+ 'joinCallFailedDueToNoNetwork',
20694
+ 'leftCall',
20695
+ /* @conditional-compile-remove(rooms) */ 'deniedPermissionToRoom',
20696
+ 'removedFromCall',
20697
+ /* @conditional-compile-remove(rooms) */ 'roomNotFound',
20698
+ /* @conditional-compile-remove(unsupported-browser) */ 'unsupportedEnvironment'
20699
+ ];
20700
+
20767
20701
  // Copyright (c) Microsoft Corporation.
20768
20702
  // Licensed under the MIT license.
20769
20703
  var __awaiter$f = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
@@ -20775,225 +20709,344 @@ var __awaiter$f = (window && window.__awaiter) || function (thisArg, _arguments,
20775
20709
  step((generator = generator.apply(thisArg, _arguments || [])).next());
20776
20710
  });
20777
20711
  };
20712
+ const ACCESS_DENIED_TEAMS_MEETING_SUB_CODE = 5854;
20713
+ const REMOTE_PSTN_USER_HUNG_UP = 560000;
20714
+ const REMOVED_FROM_CALL_SUB_CODES = [5000, 5300, REMOTE_PSTN_USER_HUNG_UP];
20715
+ /* @conditional-compile-remove(rooms) */
20716
+ const ROOM_NOT_FOUND_SUB_CODE = 5751;
20717
+ /* @conditional-compile-remove(rooms) */
20718
+ const DENIED_PERMISSION_TO_ROOM_SUB_CODE = 5828;
20778
20719
  /**
20779
20720
  * @private
20780
20721
  */
20781
- const ChatScreen = (props) => {
20782
- const { onFetchAvatarPersonaData, onRenderMessage, onRenderTypingIndicator, options, styles, fileSharing, formFactor } = props;
20783
- const defaultNumberOfChatMessagesToReload = 5;
20784
- /* @conditional-compile-remove(file-sharing) */
20785
- const [downloadErrorMessage, setDownloadErrorMessage] = React__default['default'].useState('');
20786
- const adapter = useAdapter$1();
20787
- const theme = useTheme();
20788
- React.useEffect(() => {
20789
- // Initial data should be always fetched by the composite(or external caller) instead of the adapter
20790
- const fetchData = () => __awaiter$f(void 0, void 0, void 0, function* () {
20791
- // Fetch initial data for adapter
20792
- yield adapter.fetchInitialData();
20793
- // Fetch initial set of messages. Without fetching messages here, if the Composite's adapter is changed the message thread does not load new messages.
20794
- yield adapter.loadPreviousChatMessages(defaultNumberOfChatMessagesToReload);
20795
- });
20796
- fetchData();
20797
- }, [adapter]);
20798
- const messageThreadProps = usePropsFor$2(MessageThread);
20799
- const sendBoxProps = usePropsFor$2(SendBox);
20800
- const typingIndicatorProps = usePropsFor$2(TypingIndicator);
20801
- const headerProps = useAdaptedSelector$1(getHeaderProps);
20802
- const errorBarProps = usePropsFor$2(ErrorBar);
20803
- const onRenderAvatarCallback = React.useCallback((userId, defaultOptions) => {
20804
- return (React__default['default'].createElement(AvatarPersona, Object.assign({ userId: userId, hidePersonaDetails: true }, defaultOptions, { dataProvider: onFetchAvatarPersonaData })));
20805
- }, [onFetchAvatarPersonaData]);
20806
- const messageThreadStyles = Object.assign({}, messageThreadChatCompositeStyles(theme.semanticColors.bodyBackground), styles === null || styles === void 0 ? void 0 : styles.messageThread);
20807
- const typingIndicatorStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.typingIndicator);
20808
- const sendBoxStyles = Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.sendBox);
20809
- const userId = toFlatCommunicationIdentifier(adapter.getState().userId);
20810
- const fileUploadButtonOnChange = React.useCallback((files) => {
20811
- if (!files) {
20812
- return;
20722
+ const isCameraOn = (state) => {
20723
+ if (state.call) {
20724
+ const stream = state.call.localVideoStreams.find((stream) => stream.mediaStreamType === 'Video');
20725
+ return !!stream;
20726
+ }
20727
+ else {
20728
+ if (state.devices.selectedCamera) {
20729
+ const previewOn = _isPreviewOn(state.devices);
20730
+ return previewOn;
20813
20731
  }
20814
- /* @conditional-compile-remove(file-sharing) */
20815
- const fileUploads = adapter.registerActiveFileUploads(Array.from(files));
20816
- /* @conditional-compile-remove(file-sharing) */
20817
- fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler(userId, fileUploads);
20818
- }, [adapter, fileSharing, userId]);
20819
- /* @conditional-compile-remove(file-sharing) */
20820
- 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) => {
20821
- setDownloadErrorMessage(errorMessage);
20822
- } })), [fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.downloadHandler]);
20823
- /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
20824
- const onRenderInlineAttachment = React.useCallback((attachment) => __awaiter$f(void 0, void 0, void 0, function* () {
20825
- if (attachment.previewUrl) {
20826
- const blob = yield adapter.downloadAttachments({ attachmentUrls: [attachment.previewUrl] });
20827
- return blob;
20732
+ }
20733
+ return false;
20734
+ };
20735
+ /**
20736
+ * Reduce the set of call controls visible on mobile.
20737
+ * For example do not show screenshare button.
20738
+ *
20739
+ * @private
20740
+ */
20741
+ const reduceCallControlsForMobile = (callControlOptions) => {
20742
+ if (callControlOptions === false) {
20743
+ return false;
20744
+ }
20745
+ // Ensure call controls a valid object.
20746
+ const reduceCallControlOptions = callControlOptions === true ? {} : callControlOptions || {};
20747
+ // Set to compressed mode when composite is optimized for mobile
20748
+ reduceCallControlOptions.displayType = 'compact';
20749
+ // Do not show screen share button when composite is optimized for mobile unless the developer
20750
+ // has explicitly opted in.
20751
+ if (reduceCallControlOptions.screenShareButton !== true) {
20752
+ reduceCallControlOptions.screenShareButton = false;
20753
+ }
20754
+ return reduceCallControlOptions;
20755
+ };
20756
+ var CallEndReasons;
20757
+ (function (CallEndReasons) {
20758
+ CallEndReasons[CallEndReasons["LEFT_CALL"] = 0] = "LEFT_CALL";
20759
+ CallEndReasons[CallEndReasons["ACCESS_DENIED"] = 1] = "ACCESS_DENIED";
20760
+ CallEndReasons[CallEndReasons["REMOVED_FROM_CALL"] = 2] = "REMOVED_FROM_CALL";
20761
+ CallEndReasons[CallEndReasons["ROOM_NOT_FOUND"] = 3] = "ROOM_NOT_FOUND";
20762
+ CallEndReasons[CallEndReasons["DENIED_PERMISSION_TO_ROOM"] = 4] = "DENIED_PERMISSION_TO_ROOM";
20763
+ })(CallEndReasons || (CallEndReasons = {}));
20764
+ const getCallEndReason = (call) => {
20765
+ var _a, _b, _c, _d, _e;
20766
+ const remoteParticipantsEndedArray = Array.from(Object.values(call.remoteParticipantsEnded));
20767
+ /**
20768
+ * Handle the special case in a PSTN call where removing the last user kicks the caller out of the call.
20769
+ * The code and subcode is the same as when a user is removed from a teams interop call.
20770
+ * Hence, we look at the last remote participant removed to determine if the last participant removed was a phone number.
20771
+ * If yes, the caller was kicked out of the call, but we need to show them that they left the call.
20772
+ * 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.
20773
+ */
20774
+ if (remoteParticipantsEndedArray.length === 1 &&
20775
+ communicationCommon.isPhoneNumberIdentifier(remoteParticipantsEndedArray[0].identifier) &&
20776
+ ((_a = call.callEndReason) === null || _a === void 0 ? void 0 : _a.subCode) !== REMOTE_PSTN_USER_HUNG_UP) {
20777
+ return CallEndReasons.LEFT_CALL;
20778
+ }
20779
+ if (((_b = call.callEndReason) === null || _b === void 0 ? void 0 : _b.subCode) && call.callEndReason.subCode === ACCESS_DENIED_TEAMS_MEETING_SUB_CODE) {
20780
+ return CallEndReasons.ACCESS_DENIED;
20781
+ }
20782
+ if (((_c = call.callEndReason) === null || _c === void 0 ? void 0 : _c.subCode) && REMOVED_FROM_CALL_SUB_CODES.includes(call.callEndReason.subCode)) {
20783
+ return CallEndReasons.REMOVED_FROM_CALL;
20784
+ }
20785
+ /* @conditional-compile-remove(rooms) */
20786
+ if (((_d = call.callEndReason) === null || _d === void 0 ? void 0 : _d.subCode) && call.callEndReason.subCode === ROOM_NOT_FOUND_SUB_CODE) {
20787
+ return CallEndReasons.ROOM_NOT_FOUND;
20788
+ }
20789
+ /* @conditional-compile-remove(rooms) */
20790
+ if (((_e = call.callEndReason) === null || _e === void 0 ? void 0 : _e.subCode) && call.callEndReason.subCode === DENIED_PERMISSION_TO_ROOM_SUB_CODE) {
20791
+ return CallEndReasons.DENIED_PERMISSION_TO_ROOM;
20792
+ }
20793
+ if (call.callEndReason) {
20794
+ // No error codes match, assume the user simply left the call regularly
20795
+ return CallEndReasons.LEFT_CALL;
20796
+ }
20797
+ throw new Error('No matching call end reason');
20798
+ };
20799
+ /**
20800
+ * Get the current call composite page based on the current call composite state
20801
+ *
20802
+ * @param Call - The current call state
20803
+ * @param previousCall - The state of the most recent previous call that has ended.
20804
+ *
20805
+ * @remarks - The previousCall state is needed to determine if the call has ended.
20806
+ * When the call ends a new call object is created, and so we must lookback at the
20807
+ * previous call state to understand how the call has ended. If there is no previous
20808
+ * call we know that this is a fresh call and can display the configuration page.
20809
+ *
20810
+ * @private
20811
+ */
20812
+ const getCallCompositePage = (call, previousCall, unsupportedBrowserInfo, transferCall) => {
20813
+ /* @conditional-compile-remove(unsupported-browser) */
20814
+ if (isUnsupportedEnvironment(unsupportedBrowserInfo.environmentInfo, unsupportedBrowserInfo.unsupportedBrowserVersionOptedIn)) {
20815
+ return 'unsupportedEnvironment';
20816
+ }
20817
+ /* @conditional-compile-remove(call-transfer) */
20818
+ if (transferCall !== undefined) {
20819
+ return 'transferring';
20820
+ }
20821
+ if (call) {
20822
+ // Must check for ongoing call *before* looking at any previous calls.
20823
+ // If the composite completes one call and joins another, the previous calls
20824
+ // will be populated, but not relevant for determining the page.
20825
+ // `_isInLobbyOrConnecting` needs to be checked first because `_isInCall` also returns true when call is in lobby.
20826
+ if (_isInLobbyOrConnecting(call === null || call === void 0 ? void 0 : call.state)) {
20827
+ return 'lobby';
20828
+ // `LocalHold` needs to be checked before `isInCall` since it is also a state that's considered in call.
20828
20829
  }
20829
- return [{ blobUrl: '' }];
20830
- }), [adapter]);
20831
- const AttachFileButton = React.useCallback(() => {
20832
- if (!(fileSharing === null || fileSharing === void 0 ? void 0 : fileSharing.uploadHandler)) {
20833
- return null;
20830
+ else if ((call === null || call === void 0 ? void 0 : call.state) === 'LocalHold') {
20831
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
20832
+ return 'hold';
20834
20833
  }
20835
- 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 }));
20836
- }, [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]);
20837
- return (React__default['default'].createElement(react.Stack, { className: chatContainer, grow: true },
20838
- (options === null || options === void 0 ? void 0 : options.topic) !== false && React__default['default'].createElement(ChatHeader, Object.assign({}, headerProps)),
20839
- React__default['default'].createElement(react.Stack, { className: chatArea, tokens: participantListContainerPadding, horizontal: true, grow: true },
20840
- React__default['default'].createElement(react.Stack, { className: chatWrapper, grow: true },
20841
- (options === null || options === void 0 ? void 0 : options.errorBar) !== false && React__default['default'].createElement(ErrorBar, Object.assign({}, errorBarProps)),
20842
- /* @conditional-compile-remove(file-sharing) */
20843
- React__default['default'].createElement(FileDownloadErrorBar, { onDismissDownloadErrorMessage: React.useCallback(() => {
20844
- setDownloadErrorMessage('');
20845
- }, []), fileDownloadErrorMessage: downloadErrorMessage || '' }),
20846
- React__default['default'].createElement(MessageThread, Object.assign({}, messageThreadProps, { onRenderAvatar: onRenderAvatarCallback, onRenderMessage: onRenderMessage,
20847
- /* @conditional-compile-remove(file-sharing) */
20848
- onRenderFileDownloads: onRenderFileDownloads,
20849
- /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
20850
- onFetchAttachments: onRenderInlineAttachment, numberOfChatMessagesToReload: defaultNumberOfChatMessagesToReload, styles: messageThreadStyles })),
20851
- React__default['default'].createElement(react.Stack, { className: react.mergeStyles(sendboxContainerStyles) },
20852
- React__default['default'].createElement("div", { className: react.mergeStyles(typingIndicatorContainerStyles) }, onRenderTypingIndicator ? (onRenderTypingIndicator(typingIndicatorProps.typingUsers)) : (React__default['default'].createElement(TypingIndicator, Object.assign({}, typingIndicatorProps, { styles: typingIndicatorStyles })))),
20853
- React__default['default'].createElement(react.Stack, { horizontal: formFactor === 'mobile' },
20854
- formFactor === 'mobile' && (React__default['default'].createElement(react.Stack, { verticalAlign: "center" },
20855
- React__default['default'].createElement(AttachFileButton, null))),
20856
- React__default['default'].createElement(react.Stack, { grow: true },
20857
- React__default['default'].createElement(SendBox, Object.assign({}, sendBoxProps, { autoFocus: options === null || options === void 0 ? void 0 : options.autoFocus, styles: sendBoxStyles,
20858
- /* @conditional-compile-remove(file-sharing) */
20859
- activeFileUploads: useSelector$2(fileUploadsSelector).files,
20860
- /* @conditional-compile-remove(file-sharing) */
20861
- onCancelFileUpload: adapter.cancelFileUpload }))),
20862
- formFactor !== 'mobile' && React__default['default'].createElement(AttachFileButton, null)))),
20863
- /* @conditional-compile-remove(chat-composite-participant-pane) */
20864
- (options === null || options === void 0 ? void 0 : options.participantPane) === true && (React__default['default'].createElement(ChatScreenPeoplePane, { onFetchAvatarPersonaData: onFetchAvatarPersonaData, onFetchParticipantMenuItems: props.onFetchParticipantMenuItems, isMobile: formFactor === 'mobile' })))));
20834
+ else if ((call === null || call === void 0 ? void 0 : call.state) === 'Disconnecting') {
20835
+ return 'leaving';
20836
+ }
20837
+ else if (_isInCall(call === null || call === void 0 ? void 0 : call.state)) {
20838
+ return 'call';
20839
+ }
20840
+ else {
20841
+ // When the call object has been constructed after clicking , but before 'connecting' has been
20842
+ // set on the call object, we continue to show the configuration screen.
20843
+ // The call object does not correctly reflect local device state until `call.state` moves to `connecting`.
20844
+ // Moving to the 'lobby' page too soon leads to components that depend on the `call` object to show incorrect
20845
+ // transitional state.
20846
+ return 'configuration';
20847
+ }
20848
+ }
20849
+ if (previousCall) {
20850
+ const reason = getCallEndReason(previousCall);
20851
+ /* @conditional-compile-remove(rooms) */
20852
+ switch (reason) {
20853
+ case CallEndReasons.ROOM_NOT_FOUND:
20854
+ return 'roomNotFound';
20855
+ case CallEndReasons.DENIED_PERMISSION_TO_ROOM:
20856
+ return 'deniedPermissionToRoom';
20857
+ }
20858
+ switch (reason) {
20859
+ case CallEndReasons.ACCESS_DENIED:
20860
+ return 'accessDeniedTeamsMeeting';
20861
+ case CallEndReasons.REMOVED_FROM_CALL:
20862
+ return 'removedFromCall';
20863
+ case CallEndReasons.LEFT_CALL:
20864
+ if (previousCall.diagnostics.network.latest.noNetwork) {
20865
+ return 'joinCallFailedDueToNoNetwork';
20866
+ }
20867
+ return 'leftCall';
20868
+ }
20869
+ }
20870
+ // No call state - show starting page (configuration)
20871
+ return 'configuration';
20872
+ };
20873
+ /** @private */
20874
+ const IsCallEndedPage = (
20875
+ /**
20876
+ * Explicitly listing the pages of this function intentionally.
20877
+ * This protects against adding a new composite page that should be marked as an callEndedPage.
20878
+ * EndCallPages are used to trigger onCallEnded events so this could easily be missed.
20879
+ * When you add a new composite page this will throw a compiler error. If this new page is an
20880
+ * EndCallPage ensure you update the END_CALL_PAGES. Afterwards update the `page` parameter
20881
+ * type below to allow your new page, i.e. add `| <your new page>
20882
+ */
20883
+ page) => END_CALL_PAGES.includes(page);
20884
+ /**
20885
+ * Creates a new call control options object and sets the correct values for disabling
20886
+ * the buttons provided in the `disabledControls` array.
20887
+ * Returns a new object without changing the original object.
20888
+ * @param callControlOptions options for the call control component that need to be modified.
20889
+ * @param disabledControls An array of controls to disable.
20890
+ * @returns a copy of callControlOptions with disabledControls disabled
20891
+ * @private
20892
+ */
20893
+ const disableCallControls = (callControlOptions, disabledControls) => {
20894
+ var _a;
20895
+ if (callControlOptions === false) {
20896
+ return false;
20897
+ }
20898
+ // Ensure we clone the prop if it is an object to ensure we do not mutate the original prop.
20899
+ let newOptions = (_a = (callControlOptions instanceof Object ? Object.assign({}, callControlOptions) : callControlOptions)) !== null && _a !== void 0 ? _a : {};
20900
+ if (newOptions === true || newOptions === undefined) {
20901
+ newOptions = disabledControls.reduce((acc, key) => {
20902
+ acc[key] = { disabled: true };
20903
+ return acc;
20904
+ }, {});
20905
+ }
20906
+ else {
20907
+ disabledControls.forEach((key) => {
20908
+ if (newOptions[key] !== false) {
20909
+ newOptions[key] = { disabled: true };
20910
+ }
20911
+ });
20912
+ }
20913
+ return newOptions;
20865
20914
  };
20866
-
20867
- // Copyright (c) Microsoft Corporation.
20868
20915
  /**
20869
- * A customizable UI composite for the chat experience.
20870
- *
20871
- * @remarks Chat composite min width and height are respectively 17.5rem and 20rem (280px and 320px, with default rem at 16px)
20916
+ * Check if a disabled object is provided for a button and returns if the button is disabled.
20917
+ * A button is only disabled if is explicitly set to disabled.
20872
20918
  *
20873
- * @public
20919
+ * @param option
20920
+ * @returns whether a button is disabled
20921
+ * @private
20874
20922
  */
20875
- const ChatComposite = (props) => {
20876
- const { adapter, options, onFetchAvatarPersonaData, onRenderTypingIndicator, onRenderMessage, onFetchParticipantMenuItems } = props;
20877
- const formFactor = props['formFactor'] || 'desktop';
20878
- /**
20879
- * @TODO Remove this function and pass the props directly when file-sharing is promoted to stable.
20880
- * @private
20881
- */
20882
- // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
20883
- const fileSharingOptions = () => {
20884
- /* @conditional-compile-remove(file-sharing) */
20885
- return {
20886
- fileSharing: options === null || options === void 0 ? void 0 : options.fileSharing
20887
- };
20888
- };
20889
- return (React__default['default'].createElement("div", { className: chatScreenContainerStyle },
20890
- React__default['default'].createElement(BaseProvider, Object.assign({}, props),
20891
- React__default['default'].createElement(ChatAdapterProvider, { adapter: adapter },
20892
- React__default['default'].createElement(ChatScreen, Object.assign({ formFactor: formFactor, options: options, onFetchAvatarPersonaData: onFetchAvatarPersonaData, onRenderTypingIndicator: onRenderTypingIndicator, onRenderMessage: onRenderMessage, onFetchParticipantMenuItems: onFetchParticipantMenuItems }, fileSharingOptions()))))));
20923
+ const isDisabled$2 = (option) => {
20924
+ if (option === undefined || typeof option === 'boolean') {
20925
+ return false;
20926
+ }
20927
+ return option.disabled;
20893
20928
  };
20894
-
20895
- // Copyright (c) Microsoft Corporation.
20896
- const CallAdapterContext = React.createContext(undefined);
20929
+ /* @conditional-compile-remove(call-readiness) */
20930
+ /**
20931
+ * @returns Permissions state for the camera.
20932
+ */
20933
+ const queryCameraPermissionFromPermissionsAPI = () => __awaiter$f(void 0, void 0, void 0, function* () {
20934
+ try {
20935
+ return (yield navigator.permissions.query({ name: 'camera' })).state;
20936
+ }
20937
+ catch (e) {
20938
+ console.info('permissions API is not supported by browser', e);
20939
+ return 'unsupported';
20940
+ }
20941
+ });
20942
+ /* @conditional-compile-remove(call-readiness) */
20943
+ /**
20944
+ * @returns Permissions state for the microphone.
20945
+ */
20946
+ const queryMicrophonePermissionFromPermissionsAPI = () => __awaiter$f(void 0, void 0, void 0, function* () {
20947
+ try {
20948
+ return (yield navigator.permissions.query({ name: 'microphone' })).state;
20949
+ }
20950
+ catch (e) {
20951
+ console.info('permissions API is not supported by browser', e);
20952
+ return 'unsupported';
20953
+ }
20954
+ });
20955
+ /* @conditional-compile-remove(call-readiness) */
20897
20956
  /**
20957
+ *
20958
+ * This function uses permission API to determine if device permission state is granted, prompt or denied
20959
+ * @returns whether device permission state is granted, prompt or denied
20960
+ * If permission API is not supported on this browser, permission state is set to unsupported.
20898
20961
  * @private
20899
20962
  */
20900
- const CallAdapterProvider = (props) => {
20901
- const { adapter } = props;
20902
- return React__default['default'].createElement(CallAdapterContext.Provider, { value: adapter }, props.children);
20963
+ const getDevicePermissionState = (setVideoState, setAudioState) => __awaiter$f(void 0, void 0, void 0, function* () {
20964
+ const [cameraResult, microphoneResult] = yield Promise.all([
20965
+ queryCameraPermissionFromPermissionsAPI(),
20966
+ queryMicrophonePermissionFromPermissionsAPI()
20967
+ ]);
20968
+ setVideoState(cameraResult);
20969
+ setAudioState(microphoneResult);
20970
+ });
20971
+ /* @conditional-compile-remove(unsupported-browser) */
20972
+ const isUnsupportedEnvironment = (environmentInfo, unsupportedBrowserVersionOptedIn) => {
20973
+ return !!((environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowser) === false ||
20974
+ ((environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedBrowserVersion) === false && !unsupportedBrowserVersionOptedIn) ||
20975
+ (environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.isSupportedPlatform) === false);
20903
20976
  };
20904
20977
  /**
20978
+ * Check if we are using safari browser
20905
20979
  * @private
20906
20980
  */
20907
- const useAdapter = () => {
20908
- const adapter = React.useContext(CallAdapterContext);
20909
- if (!adapter) {
20910
- throw 'Cannot find adapter please initialize before usage.';
20911
- }
20912
- return adapter;
20981
+ const _isSafari = (environmentInfo) => {
20982
+ /* @conditional-compile-remove(unsupported-browser) */
20983
+ return (environmentInfo === null || environmentInfo === void 0 ? void 0 : environmentInfo.environment.browser) === 'safari';
20913
20984
  };
20914
-
20915
- // Copyright (c) Microsoft Corporation.
20916
20985
  /**
20917
20986
  * @private
20987
+ * This is the util function to create a participant modifier for remote participantList
20988
+ * It memoize previous original participant items and only update the changed participant
20989
+ * It takes in one modifier function to generate one single participant object, it returns undefined if the object keeps unmodified
20918
20990
  */
20919
- const useAdaptedSelector = (selector, selectorProps) => {
20920
- return useSelectorWithAdaptation(selector, adaptCompositeState, selectorProps);
20991
+ const createParticipantModifier = (createModifiedParticipant) => {
20992
+ let previousParticipantState = undefined;
20993
+ let modifiedParticipants = {};
20994
+ const memoizedParticipants = {};
20995
+ return (state) => {
20996
+ var _a, _b, _c, _d;
20997
+ // if root state is the same, we don't need to update the participants
20998
+ if (((_a = state.call) === null || _a === void 0 ? void 0 : _a.remoteParticipants) !== previousParticipantState) {
20999
+ modifiedParticipants = {};
21000
+ const originalParticipants = (_b = state.call) === null || _b === void 0 ? void 0 : _b.remoteParticipants;
21001
+ for (const key in originalParticipants) {
21002
+ const modifiedParticipant = createModifiedParticipant(key, originalParticipants[key]);
21003
+ if (modifiedParticipant === undefined) {
21004
+ modifiedParticipants[key] = originalParticipants[key];
21005
+ continue;
21006
+ }
21007
+ // Generate the new item if original cached item has been changed
21008
+ if (((_c = memoizedParticipants[key]) === null || _c === void 0 ? void 0 : _c.originalRef) !== originalParticipants[key]) {
21009
+ memoizedParticipants[key] = {
21010
+ newParticipant: modifiedParticipant,
21011
+ originalRef: originalParticipants[key]
21012
+ };
21013
+ }
21014
+ // the modified participant is always coming from the memoized cache, whether is was refreshed
21015
+ // from the previous closure or not
21016
+ modifiedParticipants[key] = memoizedParticipants[key].newParticipant;
21017
+ }
21018
+ previousParticipantState = (_d = state.call) === null || _d === void 0 ? void 0 : _d.remoteParticipants;
21019
+ }
21020
+ return Object.assign(Object.assign({}, state), { call: state.call
21021
+ ? Object.assign(Object.assign({}, state.call), { remoteParticipants: modifiedParticipants }) : undefined });
21022
+ };
20921
21023
  };
20922
21024
  /**
20923
21025
  * @private
20924
21026
  */
20925
- const useSelectorWithAdaptation = (selector, adaptState, selectorProps) => {
21027
+ const dismissVideoEffectsError = (toDismiss) => {
20926
21028
  var _a;
20927
- const adapter = useAdapter();
20928
- // Keeps track of whether the current component is mounted or not. If it has unmounted, make sure we do not modify the
20929
- // state or it will cause React warnings in the console. https://skype.visualstudio.com/SPOOL/_workitems/edit/2453212
20930
- const mounted = React.useRef(false);
20931
- React.useEffect(() => {
20932
- mounted.current = true;
20933
- return () => {
20934
- mounted.current = false;
20935
- };
20936
- });
20937
- const callId = (_a = adapter.getState().call) === null || _a === void 0 ? void 0 : _a.id;
20938
- const callConfigProps = React.useMemo(() => ({
20939
- callId
20940
- }), [callId]);
20941
- const [props, setProps] = React.useState(selector(adaptState(adapter.getState()), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps));
20942
- const propRef = React.useRef(props);
20943
- propRef.current = props;
20944
- React.useEffect(() => {
20945
- const onStateChange = (state) => {
20946
- if (!mounted.current) {
20947
- return;
20948
- }
20949
- const newProps = selector(adaptState(state), selectorProps !== null && selectorProps !== void 0 ? selectorProps : callConfigProps);
20950
- if (propRef.current !== newProps) {
20951
- setProps(newProps);
20952
- }
20953
- };
20954
- adapter.onStateChange(onStateChange);
20955
- return () => {
20956
- adapter.offStateChange(onStateChange);
20957
- };
20958
- }, [adaptState, adapter, selector, selectorProps, callConfigProps]);
20959
- return props;
20960
- };
20961
- const memoizeState = memoizeOne__default['default']((userId, deviceManager, calls, latestErrors, displayName, alternateCallerId, environmentInfo) => ({
20962
- userId,
20963
- incomingCalls: {},
20964
- incomingCallsEnded: {},
20965
- callsEnded: {},
20966
- deviceManager,
20967
- callAgent: { displayName },
20968
- calls,
20969
- latestErrors,
20970
- /* @conditional-compile-remove(PSTN-calls) */
20971
- alternateCallerId,
20972
- /* @conditional-compile-remove(unsupported-browser) */
20973
- environmentInfo
20974
- }));
20975
- const memoizeCalls = memoizeOne__default['default']((call) => (call ? { [call.id]: call } : {}));
20976
- const adaptCompositeState = (compositeState) => {
20977
- return memoizeState(compositeState.userId, compositeState.devices, memoizeCalls(compositeState.call),
20978
- // This is an unsafe type expansion.
20979
- // compositeState.latestErrors can contain properties that are not valid in CallErrors.
20980
- //
20981
- // But there is no way to check for valid property names at runtime:
20982
- // - The set of valid property names is built from types in the @azure/communication-calling.
20983
- // Thus we don't have a literal array of allowed strings at runtime.
20984
- // - Due to minification / uglification, the property names from the objects at runtime can't be used
20985
- // to compare against permissible values inferred from the types.
20986
- //
20987
- // This is not a huge problem -- it simply means that our adapted selector will include some extra operations
20988
- // that are unknown to the UI component and data binding libraries. Generic handling of the errors (e.g.,
20989
- // just displaying them in some UI surface) will continue to work for these operations. Handling of
20990
- // specific operations (e.g., acting on errors related to permission issues) will ignore these operations.
20991
- compositeState.latestErrors, compositeState.displayName,
20992
- /* @conditional-compile-remove(PSTN-calls) */
20993
- compositeState.alternateCallerId,
20994
- /* @conditional-compile-remove(unsupported-browser) */
20995
- compositeState.environmentInfo);
21029
+ const now = new Date(Date.now());
21030
+ const toDismissTimestamp = (_a = toDismiss.timestamp) !== null && _a !== void 0 ? _a : now;
21031
+ // Record that this error was dismissed for the first time right now.
21032
+ return {
21033
+ dismissedAt: now > toDismissTimestamp ? now : toDismissTimestamp,
21034
+ activeSince: toDismiss.timestamp
21035
+ };
20996
21036
  };
21037
+ /* @conditional-compile-remove(video-background-effects) */
21038
+ /** @private */
21039
+ const getBackgroundEffectFromSelectedEffect = (selectedEffect) => (selectedEffect === null || selectedEffect === void 0 ? void 0 : selectedEffect.effectName) === 'blur'
21040
+ ? new communicationCallingEffects.BackgroundBlurEffect()
21041
+ : (selectedEffect === null || selectedEffect === void 0 ? void 0 : selectedEffect.effectName) === 'replacement'
21042
+ ? new communicationCallingEffects.BackgroundReplacementEffect({ backgroundImageUrl: selectedEffect.backgroundImageUrl })
21043
+ : undefined;
21044
+ /* @conditional-compile-remove(video-background-effects) */
21045
+ /**
21046
+ * @remarks this logic should mimic the onToggleCamera in the common call handlers.
21047
+ * @private
21048
+ */
21049
+ const getSelectedCameraFromAdapterState = (state) => state.devices.selectedCamera || state.devices.cameras[0];
20997
21050
 
20998
21051
  // Copyright (c) Microsoft Corporation.
20999
21052
  // Licensed under the MIT license.
@@ -26021,6 +26074,10 @@ const outboundCallStringsTrampoline = (strings) => {
26021
26074
 
26022
26075
  // Copyright (c) Microsoft Corporation.
26023
26076
  // Licensed under the MIT license.
26077
+ /**
26078
+ * @private
26079
+ */
26080
+ const pageContainer = { width: '100%', height: '100%' };
26024
26081
  /**
26025
26082
  * @private
26026
26083
  */
@@ -26081,6 +26138,8 @@ const TransferPage = (props) => {
26081
26138
  const remoteParticipants = useSelector$1(getRemoteParticipants);
26082
26139
  /* @conditional-compile-remove(call-transfer) */
26083
26140
  const transferCall = useSelector$1(getTransferCall);
26141
+ /* @conditional-compile-remove(call-transfer) */
26142
+ const [announcerString, setAnnouncerString] = React.useState(undefined);
26084
26143
  // Reduce the controls shown when mobile view is enabled.
26085
26144
  const callControlOptions = props.mobileView
26086
26145
  ? reduceCallControlsForMobile((_a = props.options) === null || _a === void 0 ? void 0 : _a.callControls)
@@ -26095,6 +26154,10 @@ const TransferPage = (props) => {
26095
26154
  }
26096
26155
  return 'transferor';
26097
26156
  }, [transferCall, transferTarget === null || transferTarget === void 0 ? void 0 : transferTarget.displayName]);
26157
+ /* @conditional-compile-remove(call-transfer) */
26158
+ React.useEffect(() => {
26159
+ setAnnouncerString(strings.transferPageNoticeString);
26160
+ }, [strings.transferPageNoticeString]);
26098
26161
  let transferTileParticipant = transferor;
26099
26162
  /* @conditional-compile-remove(call-transfer) */
26100
26163
  if (pageSubject === 'transferTarget') {
@@ -26107,16 +26170,19 @@ const TransferPage = (props) => {
26107
26170
  transferParticipantDisplayName =
26108
26171
  (_d = transferTarget === null || transferTarget === void 0 ? void 0 : transferTarget.displayName) !== null && _d !== void 0 ? _d : strings.transferPageUnknownTransferTargetDisplayName;
26109
26172
  }
26110
- return (React__default['default'].createElement(CallArrangement, { complianceBannerProps: { strings },
26111
- // Ignore errors from before current call. This avoids old errors from showing up when a user re-joins a call.
26112
- errorBarProps: ((_e = props.options) === null || _e === void 0 ? void 0 : _e.errorBar) !== false && Object.assign(Object.assign({}, errorBarProps), { ignorePremountErrors: true }), callControlProps: {
26113
- options: callControlOptions,
26114
- increaseFlyoutItemSize: props.mobileView
26115
- }, mobileView: props.mobileView, modalLayerHostId: props.modalLayerHostId, onRenderGalleryContent: () => (React__default['default'].createElement(TransferTile, { userId: transferTileParticipant ? toFlatCommunicationIdentifier(transferTileParticipant === null || transferTileParticipant === void 0 ? void 0 : transferTileParticipant.identifier) : undefined, displayName: transferParticipantDisplayName, initialsName: transferParticipantDisplayName,
26116
- /* @conditional-compile-remove(call-transfer) */
26117
- statusText: pageSubject === 'transferTarget'
26118
- ? strings.transferPageTransferTargetText
26119
- : strings.transferPageTransferorText, onRenderAvatar: props.onRenderAvatar, onFetchAvatarPersonaData: props.onFetchAvatarPersonaData })), dataUiId: 'transfer-page', updateSidePaneRenderer: props.updateSidePaneRenderer, mobileChatTabHeader: props.mobileChatTabHeader }));
26173
+ return (React__default['default'].createElement(react.Stack, { className: react.mergeStyles(pageContainer) },
26174
+ /* @conditional-compile-remove(call-transfer) */
26175
+ React__default['default'].createElement(Announcer$1, { announcementString: announcerString, ariaLive: "polite" }),
26176
+ React__default['default'].createElement(CallArrangement, { complianceBannerProps: { strings },
26177
+ // Ignore errors from before current call. This avoids old errors from showing up when a user re-joins a call.
26178
+ errorBarProps: ((_e = props.options) === null || _e === void 0 ? void 0 : _e.errorBar) !== false && Object.assign(Object.assign({}, errorBarProps), { ignorePremountErrors: true }), callControlProps: {
26179
+ options: callControlOptions,
26180
+ increaseFlyoutItemSize: props.mobileView
26181
+ }, mobileView: props.mobileView, modalLayerHostId: props.modalLayerHostId, onRenderGalleryContent: () => (React__default['default'].createElement(TransferTile, { userId: transferTileParticipant ? toFlatCommunicationIdentifier(transferTileParticipant === null || transferTileParticipant === void 0 ? void 0 : transferTileParticipant.identifier) : undefined, displayName: transferParticipantDisplayName, initialsName: transferParticipantDisplayName,
26182
+ /* @conditional-compile-remove(call-transfer) */
26183
+ statusText: pageSubject === 'transferTarget'
26184
+ ? strings.transferPageTransferTargetText
26185
+ : strings.transferPageTransferorText, onRenderAvatar: props.onRenderAvatar, onFetchAvatarPersonaData: props.onFetchAvatarPersonaData })), dataUiId: 'transfer-page', updateSidePaneRenderer: props.updateSidePaneRenderer, mobileChatTabHeader: props.mobileChatTabHeader })));
26120
26186
  };
26121
26187
  const TransferTile = (props) => {
26122
26188
  const { displayName, initialsName, userId, onRenderAvatar, onFetchAvatarPersonaData, statusText } = props;
@@ -27551,7 +27617,7 @@ class AzureCommunicationCallAdapter {
27551
27617
  const createAzureCommunicationCallAdapter = ({ userId, displayName, credential, locator,
27552
27618
  /* @conditional-compile-remove(PSTN-calls) */ alternateCallerId,
27553
27619
  /* @conditional-compile-remove(video-background-effects) */ options }) => __awaiter$3(void 0, void 0, void 0, function* () {
27554
- if (!isValidIdentifier(userId)) {
27620
+ if (!_isValidIdentifier(userId)) {
27555
27621
  throw new Error('Invalid identifier. Please provide valid identifier object.');
27556
27622
  }
27557
27623
  const callClient = createStatefulCallClient({