@azure/communication-react 1.5.1-alpha-202305160013 → 1.5.1-alpha-202305180013

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 (23) hide show
  1. package/dist/dist-cjs/communication-react/index.js +595 -373
  2. package/dist/dist-cjs/communication-react/index.js.map +1 -1
  3. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js +1 -1
  4. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js.map +1 -1
  5. package/dist/dist-esm/react-components/src/components/CameraButton.js +4 -2
  6. package/dist/dist-esm/react-components/src/components/CameraButton.js.map +1 -1
  7. package/dist/dist-esm/react-components/src/components/InputBoxComponent.js +559 -363
  8. package/dist/dist-esm/react-components/src/components/InputBoxComponent.js.map +1 -1
  9. package/dist/dist-esm/react-components/src/components/VideoEffects/VideoEffectsItem.js +1 -1
  10. package/dist/dist-esm/react-components/src/components/VideoEffects/VideoEffectsItem.js.map +1 -1
  11. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/CallArrangement.js +12 -2
  12. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/CallArrangement.js.map +1 -1
  13. package/dist/dist-esm/react-composites/src/composites/CallComposite/pages/ConfigurationPage.js +1 -1
  14. package/dist/dist-esm/react-composites/src/composites/CallComposite/pages/ConfigurationPage.js.map +1 -1
  15. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/CallWithChatComposite.js +12 -1
  16. package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/CallWithChatComposite.js.map +1 -1
  17. package/dist/dist-esm/react-composites/src/composites/ChatComposite/adapter/AzureCommunicationChatAdapter.js +4 -0
  18. package/dist/dist-esm/react-composites/src/composites/ChatComposite/adapter/AzureCommunicationChatAdapter.js.map +1 -1
  19. package/dist/dist-esm/react-composites/src/composites/common/ControlBar/CommonCallControlBar.js +3 -1
  20. package/dist/dist-esm/react-composites/src/composites/common/ControlBar/CommonCallControlBar.js.map +1 -1
  21. package/dist/dist-esm/react-composites/src/composites/common/Drawer/MoreDrawer.js +1 -1
  22. package/dist/dist-esm/react-composites/src/composites/common/Drawer/MoreDrawer.js.map +1 -1
  23. package/package.json +8 -8
@@ -164,7 +164,7 @@ const _toCommunicationIdentifier = (id) => {
164
164
  // Copyright (c) Microsoft Corporation.
165
165
  // Licensed under the MIT license.
166
166
  // GENERATED FILE. DO NOT EDIT MANUALLY.
167
- var telemetryVersion = '1.5.1-alpha-202305160013';
167
+ var telemetryVersion = '1.5.1-alpha-202305180013';
168
168
 
169
169
  // Copyright (c) Microsoft Corporation.
170
170
  /**
@@ -6036,14 +6036,16 @@ var __awaiter$w = (window && window.__awaiter) || function (thisArg, _arguments,
6036
6036
  });
6037
6037
  };
6038
6038
  /* @conditional-compile-remove(mention) */
6039
- const defaultMentionTrigger = '@';
6039
+ const DEFAULT_MENTION_TRIGGER = '@';
6040
+ /* @conditional-compile-remove(mention) */
6041
+ const MSFT_MENTION_TAG = 'msft-mention';
6040
6042
  /**
6041
6043
  * @private
6042
6044
  */
6043
6045
  const InputBoxComponent = (props) => {
6044
- const { styles, id, 'data-ui-id': dataUiId, textValue, onChange, textFieldRef, placeholderText, onKeyDown, onEnterKeyDown, supportNewline, inputClassName, errorMessage, disabled, children,
6046
+ const { styles, id, 'data-ui-id': dataUiId, textValue, onChange, textFieldRef, placeholderText, onKeyDown, onEnterKeyDown, supportNewline, inputClassName, errorMessage, disabled,
6045
6047
  /* @conditional-compile-remove(mention) */
6046
- mentionLookupOptions } = props;
6048
+ mentionLookupOptions, children } = props;
6047
6049
  const inputBoxRef = React.useRef(null);
6048
6050
  /* @conditional-compile-remove(mention) */
6049
6051
  // Current suggestion list, provided by the callback
@@ -6059,10 +6061,13 @@ const InputBoxComponent = (props) => {
6059
6061
  /* @conditional-compile-remove(mention) */
6060
6062
  const [tagsValue, setTagsValue] = React.useState([]);
6061
6063
  /* @conditional-compile-remove(mention) */
6064
+ // Index of the previous selection start in the text field
6062
6065
  const [selectionStartValue, setSelectionStartValue] = React.useState(null);
6063
6066
  /* @conditional-compile-remove(mention) */
6067
+ // Index of the previous selection end in the text field
6064
6068
  const [selectionEndValue, setSelectionEndValue] = React.useState(null);
6065
6069
  /* @conditional-compile-remove(mention) */
6070
+ // Boolean value to check if onMouseDown event should be handled during select as selection range for onMouseDown event is not updated yet and the selection range for mouse click/taps will be updated in onSelect event if needed.
6066
6071
  const [shouldHandleOnMouseDownDuringSelect, setShouldHandleOnMouseDownDuringSelect] = React.useState(true);
6067
6072
  /* @conditional-compile-remove(mention) */
6068
6073
  // Caret position in the text field
@@ -6073,24 +6078,38 @@ const InputBoxComponent = (props) => {
6073
6078
  /* @conditional-compile-remove(mention) */
6074
6079
  const localeStrings = useLocale$1().strings;
6075
6080
  /* @conditional-compile-remove(mention) */
6081
+ // Set mention suggestions
6076
6082
  const updateMentionSuggestions = React.useCallback((suggestions) => {
6077
- var _a;
6078
6083
  setMentionSuggestions(suggestions);
6079
- if (caretIndex !== undefined) {
6080
- (_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.setSelectionEnd(caretIndex);
6081
- }
6082
- }, [textFieldRef, caretIndex]);
6084
+ }, [setMentionSuggestions]);
6083
6085
  /* @conditional-compile-remove(mention) */
6084
6086
  // Parse the text and get the plain text version to display in the input box
6085
6087
  React.useEffect(() => {
6086
- const trigger = (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) || defaultMentionTrigger;
6087
- const [tags, plainText] = textToTagParser(textValue, trigger);
6088
- setInputTextValue(plainText);
6089
- setTagsValue(tags);
6088
+ const trigger = (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) || DEFAULT_MENTION_TRIGGER;
6089
+ const parsedHTMLData = textToTagParser(textValue, trigger);
6090
+ setInputTextValue(parsedHTMLData.plainText);
6091
+ setTagsValue(parsedHTMLData.tags);
6090
6092
  updateMentionSuggestions([]);
6091
6093
  }, [textValue, mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger, updateMentionSuggestions]);
6092
6094
  const mergedRootStyle = react.mergeStyles(inputBoxWrapperStyle, styles === null || styles === void 0 ? void 0 : styles.root);
6093
6095
  const mergedTextFiledStyle = react.mergeStyles(inputBoxStyle, inputClassName, props.inlineChildren ? {} : inputBoxNewLineSpaceAffordance);
6096
+ /* @conditional-compile-remove(mention) */
6097
+ React.useEffect(() => {
6098
+ var _a;
6099
+ // effect for caret index update
6100
+ if (caretIndex === undefined || textFieldRef === undefined || (textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === undefined) {
6101
+ return;
6102
+ }
6103
+ // get validated caret index between 0 and inputTextValue.length otherwise caret will be set to incorrect index
6104
+ const updatedCaretIndex = getValidatedIndexInRange({
6105
+ min: 0,
6106
+ max: inputTextValue.length,
6107
+ currentValue: caretIndex
6108
+ });
6109
+ (_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.setSelectionRange(updatedCaretIndex, updatedCaretIndex);
6110
+ setSelectionStartValue(updatedCaretIndex);
6111
+ setSelectionEndValue(updatedCaretIndex);
6112
+ }, [caretIndex, inputTextValue.length, textFieldRef, setSelectionStartValue, setSelectionEndValue]);
6094
6113
  const mergedTextContainerStyle = react.mergeStyles(textContainerStyle, styles === null || styles === void 0 ? void 0 : styles.textFieldContainer);
6095
6114
  const mergedTextFieldStyle = react.concatStyleSets(textFieldStyle, {
6096
6115
  fieldGroup: styles === null || styles === void 0 ? void 0 : styles.textField,
@@ -6105,7 +6124,7 @@ const InputBoxComponent = (props) => {
6105
6124
  const mergedChildrenStyle = react.mergeStyles(props.inlineChildren ? {} : newLineButtonsContainerStyle);
6106
6125
  /* @conditional-compile-remove(mention) */
6107
6126
  const onSuggestionSelected = React.useCallback((suggestion) => {
6108
- var _a, _b;
6127
+ var _a, _b, _c;
6109
6128
  let selectionEnd = ((_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.selectionEnd) || -1;
6110
6129
  if (selectionEnd < 0) {
6111
6130
  selectionEnd = 0;
@@ -6117,16 +6136,30 @@ const InputBoxComponent = (props) => {
6117
6136
  const mention = htmlStringForMentionSuggestion(suggestion, localeStrings);
6118
6137
  // update plain text with the mention html text
6119
6138
  const newPlainText = inputTextValue.substring(0, currentTriggerStartIndex) + mention + inputTextValue.substring(selectionEnd);
6120
- const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : defaultMentionTrigger;
6139
+ const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : DEFAULT_MENTION_TRIGGER;
6121
6140
  // update html text with updated plain text
6122
- const [updatedHTML] = updateHTML(textValue, oldPlainText, newPlainText, tagsValue, currentTriggerStartIndex, selectionEnd, mention, triggerText);
6141
+ const updatedContent = updateHTML({
6142
+ htmlText: textValue,
6143
+ oldPlainText,
6144
+ newPlainText,
6145
+ tags: tagsValue,
6146
+ startIndex: currentTriggerStartIndex,
6147
+ oldPlainTextEndIndex: selectionEnd,
6148
+ change: mention,
6149
+ mentionTrigger: triggerText
6150
+ });
6123
6151
  const displayName = getDisplayNameForMentionSuggestion(suggestion, localeStrings);
6124
- // Move the caret in the text field to the end of the mention plain text
6125
- setCaretIndex(selectionEnd + displayName.length);
6152
+ const newCaretIndex = currentTriggerStartIndex + displayName.length + triggerText.length;
6153
+ // move the caret in the text field to the end of the mention plain text
6154
+ setCaretIndex(newCaretIndex);
6155
+ setSelectionEndValue(newCaretIndex);
6156
+ setSelectionStartValue(newCaretIndex);
6126
6157
  setCurrentTriggerStartIndex(-1);
6127
6158
  updateMentionSuggestions([]);
6159
+ // set focus back to text field
6160
+ (_c = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _c === void 0 ? void 0 : _c.focus();
6128
6161
  setActiveSuggestionIndex(undefined);
6129
- onChange && onChange(undefined, updatedHTML);
6162
+ onChange && onChange(undefined, updatedContent.updatedHTML);
6130
6163
  }, [
6131
6164
  textFieldRef,
6132
6165
  inputTextValue,
@@ -6141,6 +6174,15 @@ const InputBoxComponent = (props) => {
6141
6174
  localeStrings
6142
6175
  ]);
6143
6176
  const onTextFieldKeyDown = React.useCallback((ev) => {
6177
+ /* @conditional-compile-remove(mention) */
6178
+ // caretIndex should be set to undefined when the user is typing
6179
+ setCaretIndex(undefined);
6180
+ // shouldHandleOnMouseDownDuringSelect should be set to false after the last mouse down event.
6181
+ // it shouldn't be updated in onMouseUp
6182
+ // as onMouseUp can be triggered before or after onSelect event
6183
+ // because its order depends on mouse events not selection.
6184
+ /* @conditional-compile-remove(mention) */
6185
+ setShouldHandleOnMouseDownDuringSelect(false);
6144
6186
  // Uses KeyCode 229 and which code 229 to determine if the press of the enter key is from a composition session or not (Safari only)
6145
6187
  if (ev.nativeEvent.isComposing || ev.nativeEvent.keyCode === 229 || ev.nativeEvent.which === 229) {
6146
6188
  return;
@@ -6212,24 +6254,149 @@ const InputBoxComponent = (props) => {
6212
6254
  };
6213
6255
  }, [debouncedQueryUpdate]);
6214
6256
  /* @conditional-compile-remove(mention) */
6215
- const handleOnChange = React.useCallback((event, updatedValue) => __awaiter$w(void 0, void 0, void 0, function* () {
6216
- var _b, _c;
6257
+ // Update selections index in mention to navigate by words
6258
+ const updateSelectionIndexesWithMentionIfNeeded = React.useCallback((event, inputTextValue, selectionStartValue, selectionEndValue, tagsValue) => {
6259
+ var _a, _b, _c;
6260
+ let updatedStartIndex = event.currentTarget.selectionStart;
6261
+ let updatedEndIndex = event.currentTarget.selectionEnd;
6262
+ if (event.currentTarget.selectionStart === event.currentTarget.selectionEnd &&
6263
+ event.currentTarget.selectionStart !== null &&
6264
+ event.currentTarget.selectionStart !== -1) {
6265
+ // just a caret movement/usual typing or deleting
6266
+ const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
6267
+ // don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
6268
+ if (mentionTag !== undefined &&
6269
+ mentionTag.plainTextBeginIndex !== undefined &&
6270
+ event.currentTarget.selectionStart > mentionTag.plainTextBeginIndex &&
6271
+ event.currentTarget.selectionStart < ((_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex)) {
6272
+ // get updated selection index
6273
+ const newSelectionIndex = findNewSelectionIndexForMention({
6274
+ tag: mentionTag,
6275
+ textValue: inputTextValue,
6276
+ currentSelectionIndex: event.currentTarget.selectionStart,
6277
+ previousSelectionIndex: selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : inputTextValue.length
6278
+ });
6279
+ updatedStartIndex = newSelectionIndex;
6280
+ updatedEndIndex = newSelectionIndex;
6281
+ }
6282
+ }
6283
+ else if (event.currentTarget.selectionStart !== event.currentTarget.selectionEnd) {
6284
+ // Both e.currentTarget.selectionStart !== selectionStartValue and e.currentTarget.selectionEnd !== selectionEndValue can be true when a user selects a text by double click
6285
+ if (event.currentTarget.selectionStart !== null && event.currentTarget.selectionStart !== selectionStartValue) {
6286
+ // the selection start is changed
6287
+ const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
6288
+ // don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
6289
+ if (mentionTag !== undefined &&
6290
+ mentionTag.plainTextBeginIndex !== undefined &&
6291
+ event.currentTarget.selectionStart > mentionTag.plainTextBeginIndex &&
6292
+ event.currentTarget.selectionStart < ((_b = mentionTag.plainTextEndIndex) !== null && _b !== void 0 ? _b : mentionTag.plainTextBeginIndex)) {
6293
+ updatedStartIndex = findNewSelectionIndexForMention({
6294
+ tag: mentionTag,
6295
+ textValue: inputTextValue,
6296
+ currentSelectionIndex: event.currentTarget.selectionStart,
6297
+ previousSelectionIndex: selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : inputTextValue.length
6298
+ });
6299
+ }
6300
+ }
6301
+ if (event.currentTarget.selectionEnd !== null && event.currentTarget.selectionEnd !== selectionEndValue) {
6302
+ // the selection end is changed
6303
+ const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionEnd);
6304
+ // don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
6305
+ if (mentionTag !== undefined &&
6306
+ mentionTag.plainTextBeginIndex !== undefined &&
6307
+ event.currentTarget.selectionEnd > mentionTag.plainTextBeginIndex &&
6308
+ event.currentTarget.selectionEnd < ((_c = mentionTag.plainTextEndIndex) !== null && _c !== void 0 ? _c : mentionTag.plainTextBeginIndex)) {
6309
+ updatedEndIndex = findNewSelectionIndexForMention({
6310
+ tag: mentionTag,
6311
+ textValue: inputTextValue,
6312
+ currentSelectionIndex: event.currentTarget.selectionEnd,
6313
+ previousSelectionIndex: selectionEndValue !== null && selectionEndValue !== void 0 ? selectionEndValue : inputTextValue.length
6314
+ });
6315
+ }
6316
+ }
6317
+ }
6318
+ // e.currentTarget.selectionDirection should be set to handle shift + arrow keys
6319
+ if (event.currentTarget.selectionDirection === null) {
6320
+ event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex);
6321
+ }
6322
+ else {
6323
+ event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex, event.currentTarget.selectionDirection);
6324
+ }
6325
+ setSelectionStartValue(updatedStartIndex);
6326
+ setSelectionEndValue(updatedEndIndex);
6327
+ }, [setSelectionStartValue, setSelectionEndValue]);
6328
+ /* @conditional-compile-remove(mention) */
6329
+ const handleOnSelect = React.useCallback((event, inputTextValue, tags, shouldHandleOnMouseDownDuringSelect, selectionStartValue, selectionEndValue) => {
6330
+ var _a, _b, _c;
6331
+ /* @conditional-compile-remove(mention) */
6332
+ if (shouldHandleOnMouseDownDuringSelect && event.currentTarget.selectionStart !== null) {
6333
+ // on select was triggered by mouse down
6334
+ const mentionTag = findMentionTagForSelection(tags, event.currentTarget.selectionStart);
6335
+ if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
6336
+ // handle mention click
6337
+ if (event.currentTarget.selectionDirection === null) {
6338
+ event.currentTarget.setSelectionRange(mentionTag.plainTextBeginIndex, (_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex);
6339
+ }
6340
+ else {
6341
+ event.currentTarget.setSelectionRange(mentionTag.plainTextBeginIndex, (_b = mentionTag.plainTextEndIndex) !== null && _b !== void 0 ? _b : mentionTag.plainTextBeginIndex, event.currentTarget.selectionDirection);
6342
+ }
6343
+ setSelectionStartValue(mentionTag.plainTextBeginIndex);
6344
+ setSelectionEndValue((_c = mentionTag.plainTextEndIndex) !== null && _c !== void 0 ? _c : mentionTag.plainTextBeginIndex);
6345
+ }
6346
+ else {
6347
+ setSelectionStartValue(event.currentTarget.selectionStart);
6348
+ setSelectionEndValue(event.currentTarget.selectionEnd);
6349
+ }
6350
+ }
6351
+ else {
6352
+ // selection was changed by keyboard
6353
+ updateSelectionIndexesWithMentionIfNeeded(event, inputTextValue, selectionStartValue, selectionEndValue, tags);
6354
+ }
6355
+ // don't set setShouldHandleOnMouseDownDuringSelect(false) here as setSelectionRange could trigger additional calls of onSelect event and they may not be handled correctly (because of setSelectionRange calls or rerender)
6356
+ }, [updateSelectionIndexesWithMentionIfNeeded]);
6357
+ /* @conditional-compile-remove(mention) */
6358
+ const handleOnChange = React.useCallback((event, tagsValue, htmlTextValue, inputTextValue, currentTriggerStartIndex, previousSelectionStart, previousSelectionEnd, currentSelectionStart, currentSelectionEnd, updatedValue) => __awaiter$w(void 0, void 0, void 0, function* () {
6359
+ var _b;
6360
+ if (event.currentTarget === null) {
6361
+ return;
6362
+ }
6363
+ // handle backspace change
6364
+ // onSelect is not called for backspace as selection is not changed and local caret index is outdated
6365
+ setCaretIndex(undefined);
6217
6366
  const newValue = updatedValue !== null && updatedValue !== void 0 ? updatedValue : '';
6218
- const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : defaultMentionTrigger;
6367
+ const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : DEFAULT_MENTION_TRIGGER;
6219
6368
  const newTextLength = newValue.length;
6220
- let selectionEnd = ((_c = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _c === void 0 ? void 0 : _c.selectionEnd) || -1;
6221
- selectionEnd = Math.max(0, selectionEnd);
6222
- selectionEnd = Math.min(selectionEnd, newTextLength - 1);
6369
+ // updating indexes to set between 0 and text length, otherwise selectionRange won't be set correctly
6370
+ const currentSelectionEndValue = getValidatedIndexInRange({
6371
+ min: 0,
6372
+ max: newTextLength,
6373
+ currentValue: currentSelectionEnd
6374
+ });
6375
+ const currentSelectionStartValue = getValidatedIndexInRange({
6376
+ min: 0,
6377
+ max: newTextLength,
6378
+ currentValue: currentSelectionStart
6379
+ });
6380
+ const previousSelectionStartValue = getValidatedIndexInRange({
6381
+ min: 0,
6382
+ max: inputTextValue.length,
6383
+ currentValue: previousSelectionStart
6384
+ });
6385
+ const previousSelectionEndValue = getValidatedIndexInRange({
6386
+ min: 0,
6387
+ max: inputTextValue.length,
6388
+ currentValue: previousSelectionEnd
6389
+ });
6223
6390
  // If we are enabled for lookups,
6224
6391
  if (mentionLookupOptions !== undefined) {
6225
6392
  // Look at the range of the change for a trigger character
6226
- const triggerPriorIndex = newValue.lastIndexOf(triggerText, selectionEnd - 1);
6393
+ const triggerPriorIndex = newValue.lastIndexOf(triggerText, currentSelectionEndValue - 1);
6227
6394
  // Update the caret position, if not doing a lookup
6228
6395
  setCaretPosition(textareaCaretTs.Caret.getRelativePosition(event.currentTarget));
6229
6396
  if (triggerPriorIndex !== undefined) {
6230
6397
  // trigger is found
6231
6398
  const isSpaceBeforeTrigger = newValue.substring(triggerPriorIndex - 1, triggerPriorIndex) === ' ';
6232
- const wordAtSelection = newValue.substring(triggerPriorIndex, selectionEnd);
6399
+ const wordAtSelection = newValue.substring(triggerPriorIndex, currentSelectionEndValue);
6233
6400
  let tagIndex = currentTriggerStartIndex;
6234
6401
  if (!isSpaceBeforeTrigger && triggerPriorIndex !== 0) {
6235
6402
  //no space before the trigger <- continuation of the previous word
@@ -6238,7 +6405,7 @@ const InputBoxComponent = (props) => {
6238
6405
  }
6239
6406
  else if (wordAtSelection === triggerText) {
6240
6407
  // start of the mention
6241
- tagIndex = selectionEnd - triggerText.length;
6408
+ tagIndex = currentSelectionEndValue - triggerText.length;
6242
6409
  if (tagIndex < 0) {
6243
6410
  tagIndex = 0;
6244
6411
  }
@@ -6260,88 +6427,42 @@ const InputBoxComponent = (props) => {
6260
6427
  }
6261
6428
  let result = '';
6262
6429
  if (tagsValue.length === 0) {
6263
- // no tags in the string, textValue is a sting
6430
+ // no tags in the string and newValue should be used as a result string
6264
6431
  result = newValue;
6265
6432
  }
6266
6433
  else {
6267
- // there are tags in the text value, textValue is html string
6268
- const { changeStart, oldChangeEnd, newChangeEnd } = findStringsDiffIndexes(inputTextValue, newValue, selectionEnd);
6269
- // get updated html string
6434
+ // there are tags in the text value and htmlTextValue is html string
6435
+ // find diff between old and new text
6436
+ const { changeStart, oldChangeEnd, newChangeEnd } = findStringsDiffIndexes({
6437
+ oldText: inputTextValue,
6438
+ newText: newValue,
6439
+ previousSelectionStart: previousSelectionStartValue,
6440
+ previousSelectionEnd: previousSelectionEndValue,
6441
+ currentSelectionStart: currentSelectionStartValue,
6442
+ currentSelectionEnd: currentSelectionEndValue
6443
+ });
6270
6444
  const change = newValue.substring(changeStart, newChangeEnd);
6271
- const [updatedHTML, updatedChangeNewEndIndex] = updateHTML(textValue, inputTextValue, newValue, tagsValue, changeStart, oldChangeEnd, change, triggerText);
6272
- result = updatedHTML;
6273
- if (updatedChangeNewEndIndex !== null) {
6274
- if ((change.length === 1 && event.currentTarget.selectionStart === event.currentTarget.selectionEnd) || // simple input
6275
- (change.length === 0 && newChangeEnd === changeStart) //delete
6276
- ) {
6277
- setCaretIndex(updatedChangeNewEndIndex);
6278
- }
6445
+ // get updated html string
6446
+ const updatedContent = updateHTML({
6447
+ htmlText: htmlTextValue,
6448
+ oldPlainText: inputTextValue,
6449
+ newPlainText: newValue,
6450
+ tags: tagsValue,
6451
+ startIndex: changeStart,
6452
+ oldPlainTextEndIndex: oldChangeEnd,
6453
+ change,
6454
+ mentionTrigger: triggerText
6455
+ });
6456
+ result = updatedContent.updatedHTML;
6457
+ // update caret index if needed
6458
+ if (updatedContent.updatedSelectionIndex !== null) {
6459
+ setCaretIndex(updatedContent.updatedSelectionIndex);
6460
+ setSelectionEndValue(updatedContent.updatedSelectionIndex);
6461
+ setSelectionStartValue(updatedContent.updatedSelectionIndex);
6279
6462
  }
6280
6463
  }
6281
6464
  onChange && onChange(event, result);
6282
- }), [
6283
- onChange,
6284
- mentionLookupOptions,
6285
- tagsValue,
6286
- textValue,
6287
- inputTextValue,
6288
- currentTriggerStartIndex,
6289
- setCaretIndex,
6290
- setCaretPosition,
6291
- updateMentionSuggestions,
6292
- debouncedQueryUpdate,
6293
- textFieldRef
6294
- ]);
6295
- /* @conditional-compile-remove(mention) */
6296
- const updateSelectionIndexesWithMentionIfNeeded = (event) => {
6297
- var _a;
6298
- let updatedStartIndex = event.currentTarget.selectionStart;
6299
- let updatedEndIndex = event.currentTarget.selectionEnd;
6300
- if (event.currentTarget.selectionStart === event.currentTarget.selectionEnd &&
6301
- event.currentTarget.selectionStart !== null &&
6302
- event.currentTarget.selectionStart !== -1) {
6303
- const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
6304
- if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
6305
- if (selectionStartValue === null) {
6306
- updatedStartIndex = mentionTag.plainTextBeginIndex;
6307
- updatedEndIndex = (_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex;
6308
- }
6309
- else {
6310
- const newSelectionIndex = findNewSelectionIndexForMention(mentionTag, inputTextValue, event.currentTarget.selectionStart, selectionStartValue);
6311
- updatedStartIndex = newSelectionIndex;
6312
- updatedEndIndex = newSelectionIndex;
6313
- }
6314
- }
6315
- }
6316
- else if (event.currentTarget.selectionStart !== event.currentTarget.selectionEnd) {
6317
- // Both e.currentTarget.selectionStart !== selectionStartValue and e.currentTarget.selectionEnd !== selectionEndValue can be true when a user selects a text by double click
6318
- if (event.currentTarget.selectionStart !== null && event.currentTarget.selectionStart !== selectionStartValue) {
6319
- // the selection start is changed
6320
- const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
6321
- if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
6322
- //TODO: here it takes -1 when it shouldn't, update selectionstart and end with mouse move and or touch move
6323
- updatedStartIndex = findNewSelectionIndexForMention(mentionTag, inputTextValue, event.currentTarget.selectionStart, selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : -1);
6324
- }
6325
- }
6326
- if (event.currentTarget.selectionEnd !== null && event.currentTarget.selectionEnd !== selectionEndValue) {
6327
- // the selection end is changed
6328
- const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionEnd);
6329
- if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
6330
- //TODO: here it takes -1 when it shouldn't, update selectionstart and end with mouse move and or touch move
6331
- updatedEndIndex = findNewSelectionIndexForMention(mentionTag, inputTextValue, event.currentTarget.selectionEnd, selectionEndValue !== null && selectionEndValue !== void 0 ? selectionEndValue : -1);
6332
- }
6333
- }
6334
- }
6335
- // e.currentTarget.selectionDirection should be set to handle shift + arrow keys
6336
- if (event.currentTarget.selectionDirection === null) {
6337
- event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex);
6338
- }
6339
- else {
6340
- event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex, event.currentTarget.selectionDirection);
6341
- }
6342
- setSelectionStartValue(updatedStartIndex);
6343
- setSelectionEndValue(updatedEndIndex);
6344
- };
6465
+ }), [onChange, mentionLookupOptions, setCaretIndex, setCaretPosition, updateMentionSuggestions, debouncedQueryUpdate]);
6345
6466
  const getInputFieldTextValue = () => {
6346
6467
  /* @conditional-compile-remove(mention) */
6347
6468
  return inputTextValue;
@@ -6352,60 +6473,51 @@ const InputBoxComponent = (props) => {
6352
6473
  updateMentionSuggestions([]);
6353
6474
  } })),
6354
6475
  React__default['default'].createElement(react.TextField, { autoFocus: props.autoFocus === 'sendBoxTextField', "data-ui-id": dataUiId, multiline: true, autoAdjustHeight: true, multiple: false, resizable: false, componentRef: textFieldRef, id: id, inputClassName: mergedTextFiledStyle, placeholder: placeholderText, value: getInputFieldTextValue(), onChange: (e, newValue) => {
6476
+ // Remove when switching to react 17+, currently needed because of https://legacy.reactjs.org/docs/legacy-event-pooling.html
6477
+ /* @conditional-compile-remove(mention) */
6478
+ // Prevents React from resetting event's properties
6479
+ e.persist();
6355
6480
  /* @conditional-compile-remove(mention) */
6356
6481
  setInputTextValue(newValue !== null && newValue !== void 0 ? newValue : '');
6357
6482
  /* @conditional-compile-remove(mention) */
6358
- handleOnChange(e, newValue);
6483
+ handleOnChange(e, tagsValue, textValue, inputTextValue, currentTriggerStartIndex, selectionStartValue === null ? undefined : selectionStartValue, selectionEndValue === null ? undefined : selectionEndValue, e.currentTarget.selectionStart === null ? undefined : e.currentTarget.selectionStart, e.currentTarget.selectionEnd === null ? undefined : e.currentTarget.selectionEnd, newValue);
6359
6484
  /* @conditional-compile-remove(mention) */
6360
6485
  return;
6361
6486
  },
6362
6487
  /* @conditional-compile-remove(mention) */
6363
6488
  onSelect: (e) => {
6364
- var _a, _b, _c;
6489
+ // update selection if needed
6365
6490
  if (caretIndex !== undefined) {
6366
- e.currentTarget.setSelectionRange(caretIndex, caretIndex);
6367
6491
  setCaretIndex(undefined);
6368
- return;
6369
- }
6370
- //TODO: need to check to navigate before/after space correctly in tag + when selecting by mouse
6371
- /* @conditional-compile-remove(mention) */
6372
- if (shouldHandleOnMouseDownDuringSelect &&
6373
- e.currentTarget.selectionStart !== null &&
6374
- e.currentTarget.selectionStart === e.currentTarget.selectionEnd) {
6375
- // handle mention click
6376
- const mentionTag = findMentionTagForSelection(tagsValue, e.currentTarget.selectionStart);
6377
- if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
6378
- if (e.currentTarget.selectionDirection === null) {
6379
- e.currentTarget.setSelectionRange(mentionTag.plainTextBeginIndex, (_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex);
6380
- }
6381
- else {
6382
- e.currentTarget.setSelectionRange(mentionTag.plainTextBeginIndex, (_b = mentionTag.plainTextEndIndex) !== null && _b !== void 0 ? _b : mentionTag.plainTextBeginIndex, e.currentTarget.selectionDirection);
6383
- }
6384
- setSelectionStartValue(mentionTag.plainTextBeginIndex);
6385
- setSelectionEndValue((_c = mentionTag.plainTextEndIndex) !== null && _c !== void 0 ? _c : mentionTag.plainTextBeginIndex);
6386
- }
6387
- else {
6388
- setSelectionStartValue(e.currentTarget.selectionStart);
6389
- setSelectionEndValue(e.currentTarget.selectionEnd);
6492
+ // sometimes setting selectionRage in effect for updating caretIndex doesn't work as expected and onSelect should handle this case
6493
+ if (caretIndex !== e.currentTarget.selectionStart || caretIndex !== e.currentTarget.selectionEnd) {
6494
+ e.currentTarget.setSelectionRange(caretIndex, caretIndex);
6390
6495
  }
6496
+ return;
6391
6497
  }
6392
- else {
6393
- updateSelectionIndexesWithMentionIfNeeded(e);
6394
- }
6395
- /* @conditional-compile-remove(mention) */
6396
- setShouldHandleOnMouseDownDuringSelect(false);
6397
- }, onMouseDown: () => {
6498
+ handleOnSelect(e, inputTextValue, tagsValue, shouldHandleOnMouseDownDuringSelect, selectionStartValue, selectionEndValue);
6499
+ },
6500
+ /* @conditional-compile-remove(mention) */
6501
+ onMouseDown: () => {
6398
6502
  // as events order is onMouseDown -> onSelect -> onClick
6399
6503
  // onClick and onMouseDown can't handle clicking on mention event because
6400
- // onClick has wrong range as it's called after onSelect
6401
- // onMouseDown doesn't have correct selectionRange yet
6504
+ // onMouseDown doesn't have correct selectionRange yet and
6505
+ // onClick already has wrong range as it's called after onSelect that updates the selection range
6402
6506
  // so we need to handle onMouseDown to prevent onSelect default behavior
6403
- /* @conditional-compile-remove(mention) */
6404
6507
  setShouldHandleOnMouseDownDuringSelect(true);
6405
- }, onTouchStart: () => {
6508
+ },
6509
+ /* @conditional-compile-remove(mention) */
6510
+ onTouchStart: () => {
6406
6511
  // see onMouseDown for more details
6407
- /* @conditional-compile-remove(mention) */
6408
6512
  setShouldHandleOnMouseDownDuringSelect(true);
6513
+ },
6514
+ /* @conditional-compile-remove(mention) */
6515
+ onBlur: () => {
6516
+ // setup all flags to default values when text field loses focus
6517
+ setShouldHandleOnMouseDownDuringSelect(false);
6518
+ setCaretIndex(undefined);
6519
+ setSelectionStartValue(null);
6520
+ setSelectionEndValue(null);
6409
6521
  }, autoComplete: "off", onKeyDown: onTextFieldKeyDown, styles: mergedTextFieldStyle, disabled: disabled, errorMessage: errorMessage, onRenderSuffix: onRenderChildren, elementRef: inputBoxRef }))));
6410
6522
  };
6411
6523
  /**
@@ -6434,77 +6546,93 @@ const InputBoxButton = (props) => {
6434
6546
  };
6435
6547
  /* @conditional-compile-remove(mention) */
6436
6548
  /**
6437
- * Find mention tag if selection is inside of it
6549
+ * Get validated value for index between min and max values. If currentValue is not defined, -1 will be used instead.
6550
+ *
6551
+ * @private
6552
+ * @param props - Props for finding a valid index in range.
6553
+ * @returns Valid index in the range.
6554
+ */
6555
+ const getValidatedIndexInRange = (props) => {
6556
+ const { min, max, currentValue } = props;
6557
+ let updatedValue = currentValue !== null && currentValue !== void 0 ? currentValue : -1;
6558
+ updatedValue = Math.max(min, updatedValue);
6559
+ updatedValue = Math.min(updatedValue, max);
6560
+ return updatedValue;
6561
+ };
6562
+ /* @conditional-compile-remove(mention) */
6563
+ /**
6564
+ * Find mention tag for selection if exists.
6438
6565
  *
6439
6566
  * @private
6567
+ * @param tags - Existing list of tags.
6568
+ * @param selection - Selection index.
6569
+ * @returns Mention tag if exists, otherwise undefined.
6440
6570
  */
6441
6571
  const findMentionTagForSelection = (tags, selection) => {
6442
6572
  let mentionTag = undefined;
6443
6573
  for (let i = 0; i < tags.length; i++) {
6444
6574
  const tag = tags[i];
6445
- let plainTextEndIndex = 0;
6446
- if (tag.plainTextEndIndex !== undefined && tag.closeTagIdx !== undefined) {
6447
- // close tag exists
6448
- plainTextEndIndex = tag.plainTextEndIndex;
6449
- }
6450
- else if (tag.plainTextBeginIndex !== undefined) {
6451
- //no close tag
6452
- plainTextEndIndex = tag.plainTextBeginIndex;
6453
- }
6454
- if (tag.subTags !== undefined && tag.subTags.length !== 0) {
6455
- const selectedTag = findMentionTagForSelection(tag.subTags, selection);
6456
- if (selectedTag !== undefined) {
6457
- mentionTag = selectedTag;
6575
+ const closingTagInfo = getTagClosingTagInfo(tag);
6576
+ if (tag.plainTextBeginIndex !== undefined && tag.plainTextBeginIndex > selection) {
6577
+ // no need to check further as the selection is before the tag
6578
+ break;
6579
+ }
6580
+ else if (tag.plainTextBeginIndex !== undefined &&
6581
+ tag.plainTextBeginIndex <= selection &&
6582
+ selection <= closingTagInfo.plainTextEndIndex) {
6583
+ // no need to check if tag doesn't contain selection
6584
+ if (tag.subTags !== undefined && tag.subTags.length !== 0) {
6585
+ const selectedTag = findMentionTagForSelection(tag.subTags, selection);
6586
+ if (selectedTag !== undefined) {
6587
+ mentionTag = selectedTag;
6588
+ break;
6589
+ }
6590
+ }
6591
+ else if (tag.tagType === MSFT_MENTION_TAG) {
6592
+ mentionTag = tag;
6458
6593
  break;
6459
6594
  }
6460
6595
  }
6461
- else if (tag.tagType === 'msft-mention' &&
6462
- tag.plainTextBeginIndex !== undefined &&
6463
- tag.plainTextBeginIndex < selection &&
6464
- selection < plainTextEndIndex) {
6465
- mentionTag = tag;
6466
- break;
6467
- }
6468
6596
  }
6469
6597
  return mentionTag;
6470
6598
  };
6471
6599
  /* @conditional-compile-remove(mention) */
6472
6600
  /**
6473
- * Go through tags and find a new the selection index if it is inside of a mention tag
6601
+ * Find a new the selection index.
6474
6602
  *
6475
6603
  * @private
6604
+ * @param props - Props for finding new selection index for mention.
6605
+ * @returns New selection index if it is inside of a mention tag, otherwise the current selection.
6476
6606
  */
6477
- const findNewSelectionIndexForMention = (tag, textValue, selection, previousSelection) => {
6607
+ const findNewSelectionIndexForMention = (props) => {
6478
6608
  var _a;
6479
- if (tag.plainTextBeginIndex === undefined ||
6480
- tag.tagType !== 'msft-mention' ||
6481
- selection === previousSelection ||
6609
+ const { tag, textValue, currentSelectionIndex, previousSelectionIndex } = props;
6610
+ // check if this is a mention tag and selection should be updated
6611
+ if (tag.tagType !== MSFT_MENTION_TAG ||
6612
+ tag.plainTextBeginIndex === undefined ||
6613
+ currentSelectionIndex === previousSelectionIndex ||
6482
6614
  tag.plainTextEndIndex === undefined) {
6483
- return selection;
6615
+ return currentSelectionIndex;
6484
6616
  }
6485
6617
  let spaceIndex = 0;
6486
- if (selection <= previousSelection) {
6487
- // the cursor is moved to the left
6488
- spaceIndex = textValue.lastIndexOf(' ', selection !== null && selection !== void 0 ? selection : 0);
6618
+ if (currentSelectionIndex <= previousSelectionIndex) {
6619
+ // the cursor is moved to the left, find the last index before the cursor
6620
+ spaceIndex = textValue.lastIndexOf(' ', currentSelectionIndex !== null && currentSelectionIndex !== void 0 ? currentSelectionIndex : 0);
6489
6621
  if (spaceIndex === -1) {
6490
- // no space before the selection
6622
+ // no space before the selection, use the beginning of the tag
6491
6623
  spaceIndex = tag.plainTextBeginIndex;
6492
6624
  }
6493
6625
  }
6494
6626
  else {
6495
- // the cursor is moved to the right
6496
- spaceIndex = textValue.indexOf(' ', selection !== null && selection !== void 0 ? selection : 0);
6627
+ // the cursor is moved to the right, find the fist index after the cursor
6628
+ spaceIndex = textValue.indexOf(' ', currentSelectionIndex !== null && currentSelectionIndex !== void 0 ? currentSelectionIndex : 0);
6497
6629
  if (spaceIndex === -1) {
6498
- // no space after the selection
6630
+ // no space after the selection, use the end of the tag
6499
6631
  spaceIndex = (_a = tag.plainTextEndIndex) !== null && _a !== void 0 ? _a : tag.plainTextBeginIndex;
6500
6632
  }
6501
6633
  }
6502
- if (spaceIndex < tag.plainTextBeginIndex) {
6503
- spaceIndex = tag.plainTextBeginIndex;
6504
- }
6505
- else if (spaceIndex > tag.plainTextEndIndex) {
6506
- spaceIndex = tag.plainTextEndIndex;
6507
- }
6634
+ spaceIndex = Math.max(tag.plainTextBeginIndex, spaceIndex);
6635
+ spaceIndex = Math.min(tag.plainTextEndIndex, spaceIndex);
6508
6636
  return spaceIndex;
6509
6637
  };
6510
6638
  /* @conditional-compile-remove(mention) */
@@ -6512,10 +6640,21 @@ const findNewSelectionIndexForMention = (tag, textValue, selection, previousSele
6512
6640
  * Handle mention tag edit and by word deleting
6513
6641
  *
6514
6642
  * @private
6643
+ * @param props - Props for mention update HTML function.
6644
+ * @returns Updated texts and indexes.
6515
6645
  */
6516
- const handleMentionTagUpdate = (htmlText, oldPlainText, lastProcessedHTMLIndex, processedChange, tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength) => {
6517
- if (tag.tagType !== 'msft-mention' || tag.plainTextBeginIndex === undefined) {
6518
- return ['', processedChange, lastProcessedHTMLIndex, null];
6646
+ const handleMentionTagUpdate = (props) => {
6647
+ const { htmlText, oldPlainText, change, tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength } = props;
6648
+ let processedChange = props.processedChange;
6649
+ let lastProcessedHTMLIndex = props.lastProcessedHTMLIndex;
6650
+ if (tag.tagType !== MSFT_MENTION_TAG || tag.plainTextBeginIndex === undefined) {
6651
+ // not a mention tag
6652
+ return {
6653
+ result: '',
6654
+ updatedChange: processedChange,
6655
+ htmlIndex: lastProcessedHTMLIndex,
6656
+ plainTextSelectionEndIndex: null
6657
+ };
6519
6658
  }
6520
6659
  let result = '';
6521
6660
  let plainTextSelectionEndIndex = null;
@@ -6538,9 +6677,11 @@ const handleMentionTagUpdate = (htmlText, oldPlainText, lastProcessedHTMLIndex,
6538
6677
  }
6539
6678
  isSpaceLengthHandled = true;
6540
6679
  if (rangeStart === -1 || rangeStart === undefined || rangeStart < tag.plainTextBeginIndex) {
6680
+ // rangeStart should be at least equal to tag.plainTextBeginIndex
6541
6681
  rangeStart = tag.plainTextBeginIndex;
6542
6682
  }
6543
6683
  if (rangeEnd > plainTextEndIndex) {
6684
+ // rangeEnd should be at most equal to plainTextEndIndex
6544
6685
  rangeEnd = plainTextEndIndex;
6545
6686
  }
6546
6687
  if (rangeStart === tag.plainTextBeginIndex && rangeEnd === plainTextEndIndex) {
@@ -6560,28 +6701,61 @@ const handleMentionTagUpdate = (htmlText, oldPlainText, lastProcessedHTMLIndex,
6560
6701
  }
6561
6702
  endChangeDiff = rangeEnd - tag.plainTextBeginIndex - mentionTagLength;
6562
6703
  result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length + startChangeDiff);
6563
- // plainTextSelectionEndIndex = rangeStart + processedChange.length;
6704
+ if (startIndex < tag.plainTextBeginIndex) {
6705
+ // if the change is before the tag, the selection should start from startIndex (rangeStart will be equal to tag.plainTextBeginIndex)
6706
+ plainTextSelectionEndIndex = startIndex + change.length;
6707
+ }
6708
+ else {
6709
+ // if the change is inside the tag, the selection should start with rangeStart
6710
+ plainTextSelectionEndIndex = rangeStart + processedChange.length;
6711
+ }
6564
6712
  lastProcessedHTMLIndex = tag.openTagIdx + tag.openTagBody.length + endChangeDiff;
6565
6713
  // processed change should not be changed as it should be added after the tag
6566
6714
  }
6567
- return [result, processedChange, lastProcessedHTMLIndex, plainTextSelectionEndIndex];
6715
+ return { result, updatedChange: processedChange, htmlIndex: lastProcessedHTMLIndex, plainTextSelectionEndIndex };
6568
6716
  };
6569
6717
  /* @conditional-compile-remove(mention) */
6570
6718
  /**
6571
- * Go through the text and update it with the changed text
6719
+ * Get closing tag information if exists otherwise return information as for self closing tag
6572
6720
  *
6573
6721
  * @private
6722
+ * @param tag - Tag data.
6723
+ * @returns Closing tag information for the provided tag.
6574
6724
  */
6575
- const updateHTML = (htmlText, oldPlainText, newPlainText, tags, startIndex, oldPlainTextEndIndex, change, mentionTrigger) => {
6576
- let result = '';
6577
- if (tags.length === 0) {
6578
- // no tags added yet
6579
- return [newPlainText, null];
6725
+ const getTagClosingTagInfo = (tag) => {
6726
+ let plainTextEndIndex = 0;
6727
+ let closeTagIdx = 0;
6728
+ let closeTagLength = 0;
6729
+ if (tag.plainTextEndIndex !== undefined && tag.closeTagIdx !== undefined) {
6730
+ // close tag exists
6731
+ plainTextEndIndex = tag.plainTextEndIndex;
6732
+ closeTagIdx = tag.closeTagIdx;
6733
+ // tag.tagType.length + </>
6734
+ closeTagLength = tag.tagType.length + 3;
6580
6735
  }
6581
- if (startIndex === 0 && oldPlainTextEndIndex === oldPlainText.length) {
6582
- // the whole text is changed
6583
- return [newPlainText, null];
6736
+ else if (tag.plainTextBeginIndex !== undefined) {
6737
+ // no close tag
6738
+ plainTextEndIndex = tag.plainTextBeginIndex;
6739
+ closeTagIdx = tag.openTagIdx + tag.openTagBody.length;
6740
+ closeTagLength = 0;
6584
6741
  }
6742
+ return { plainTextEndIndex, closeTagIdx, closeTagLength };
6743
+ };
6744
+ /* @conditional-compile-remove(mention) */
6745
+ /**
6746
+ * Go through the text and update it with the changed text
6747
+ *
6748
+ * @private
6749
+ * @param props - Props for update HTML function.
6750
+ * @returns Updated HTML and selection index if the selection index should be set.
6751
+ */
6752
+ const updateHTML = (props) => {
6753
+ const { htmlText, oldPlainText, newPlainText, tags, startIndex, oldPlainTextEndIndex, change, mentionTrigger } = props;
6754
+ if (tags.length === 0 || (startIndex === 0 && oldPlainTextEndIndex === oldPlainText.length - 1)) {
6755
+ // no tags added yet or the whole text is changed
6756
+ return { updatedHTML: newPlainText, updatedSelectionIndex: null };
6757
+ }
6758
+ let result = '';
6585
6759
  let lastProcessedHTMLIndex = 0;
6586
6760
  // the value can be updated with empty string when the change covers more than 1 place (tag + before or after the tag)
6587
6761
  // in this case change won't be added as part of the tag
@@ -6592,7 +6766,7 @@ const updateHTML = (htmlText, oldPlainText, newPlainText, tags, startIndex, oldP
6592
6766
  let processedChange = change;
6593
6767
  // end tag plain text index of the last processed tag
6594
6768
  let lastProcessedPlainTextTagEndIndex = 0;
6595
- // as some tags/text can be removed fully, selectionEnd should be updated correctly
6769
+ // as some tags/text can be removed fully, selection should be updated correctly
6596
6770
  let changeNewEndIndex = null;
6597
6771
  for (let i = 0; i < tags.length; i++) {
6598
6772
  const tag = tags[i];
@@ -6601,165 +6775,225 @@ const updateHTML = (htmlText, oldPlainText, newPlainText, tags, startIndex, oldP
6601
6775
  }
6602
6776
  // all plain text indexes includes trigger length for the mention that shouldn't be included in
6603
6777
  // htmlText.substring because html strings don't include the trigger
6604
- // mentionTagLength will be set only for 'msft-mention', otherwise should be 0
6778
+ // mentionTagLength will be set only for mention tag, otherwise should be 0
6605
6779
  let mentionTagLength = 0;
6606
6780
  let isMentionTag = false;
6607
- if (tag.tagType === 'msft-mention') {
6781
+ if (tag.tagType === MSFT_MENTION_TAG) {
6608
6782
  mentionTagLength = mentionTrigger.length;
6609
6783
  isMentionTag = true;
6610
6784
  }
6611
- //change start is before the open tag
6612
6785
  if (startIndex <= tag.plainTextBeginIndex) {
6786
+ // change start is before the open tag
6613
6787
  // Math.max(lastProcessedPlainTextTagEndIndex, startIndex) is used as startIndex may not be in [[previous tag].plainTextEndIndex - tag.plainTextBeginIndex] range
6614
6788
  const startChangeDiff = tag.plainTextBeginIndex - Math.max(lastProcessedPlainTextTagEndIndex, startIndex);
6615
6789
  result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx - startChangeDiff) + processedChange;
6790
+ processedChange = '';
6616
6791
  if (oldPlainTextEndIndex <= tag.plainTextBeginIndex) {
6617
6792
  // the whole change is before tag start
6618
- // oldPlainTextEndIndex already includes mentionTag length
6793
+ // mentionTag length can be ignored here as the change is before the tag
6619
6794
  const endChangeDiff = tag.plainTextBeginIndex - oldPlainTextEndIndex;
6620
6795
  lastProcessedHTMLIndex = tag.openTagIdx - endChangeDiff;
6621
- processedChange = '';
6622
6796
  // the change is handled; exit
6623
6797
  break;
6624
6798
  }
6625
6799
  else {
6626
6800
  // change continues in the tag
6627
6801
  lastProcessedHTMLIndex = tag.openTagIdx;
6628
- processedChange = '';
6629
6802
  // proceed to the next check
6630
6803
  }
6631
6804
  }
6632
- let plainTextEndIndex = 0;
6633
- let closeTagIdx = 0;
6634
- let closeTagLength = 0;
6635
- if (tag.plainTextEndIndex !== undefined && tag.closeTagIdx !== undefined) {
6636
- // close tag exists
6637
- plainTextEndIndex = tag.plainTextEndIndex;
6638
- closeTagIdx = tag.closeTagIdx;
6639
- // tag.tagType.length + </>
6640
- closeTagLength = tag.tagType.length + 3;
6641
- }
6642
- else {
6643
- // no close tag
6644
- plainTextEndIndex = tag.plainTextBeginIndex;
6645
- closeTagIdx = tag.openTagIdx + tag.openTagBody.length;
6646
- closeTagLength = 0;
6647
- }
6648
- if (startIndex < plainTextEndIndex) {
6805
+ const closingTagInfo = getTagClosingTagInfo(tag);
6806
+ if (startIndex <= closingTagInfo.plainTextEndIndex) {
6649
6807
  // change started before the end tag
6650
- if (startIndex <= tag.plainTextBeginIndex && oldPlainTextEndIndex === plainTextEndIndex) {
6808
+ if (startIndex <= tag.plainTextBeginIndex && oldPlainTextEndIndex === closingTagInfo.plainTextEndIndex) {
6651
6809
  // the change is a tag or starts before the tag
6652
6810
  // tag should be removed, no matter if there are subtags
6653
6811
  result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx) + processedChange;
6654
6812
  processedChange = '';
6655
- lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
6813
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
6656
6814
  // the change is handled; exit
6657
6815
  break;
6658
6816
  }
6659
- else if (startIndex >= tag.plainTextBeginIndex && oldPlainTextEndIndex < plainTextEndIndex) {
6660
- // edge case: the change is between tag
6817
+ else if (startIndex >= tag.plainTextBeginIndex && oldPlainTextEndIndex <= closingTagInfo.plainTextEndIndex) {
6818
+ // the change is between the tag
6661
6819
  if (isMentionTag) {
6662
6820
  if (change !== '') {
6663
- // mention tag should be deleted when user tries to edit it
6664
- result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx) + processedChange;
6665
- changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
6821
+ if (startIndex !== tag.plainTextBeginIndex && startIndex !== closingTagInfo.plainTextEndIndex) {
6822
+ // mention tag should be deleted when user tries to edit it in the middle
6823
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx) + processedChange;
6824
+ changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
6825
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
6826
+ }
6827
+ else if (startIndex === tag.plainTextBeginIndex) {
6828
+ // non empty change at the beginning of the mention tag to be added before the mention tag
6829
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx) + processedChange;
6830
+ changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
6831
+ lastProcessedHTMLIndex = tag.openTagIdx;
6832
+ }
6833
+ else if (startIndex === closingTagInfo.plainTextEndIndex) {
6834
+ // non empty change at the end of the mention tag to be added after the mention tag
6835
+ result +=
6836
+ htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength) +
6837
+ processedChange;
6838
+ changeNewEndIndex = closingTagInfo.plainTextEndIndex + processedChange.length;
6839
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
6840
+ }
6666
6841
  processedChange = '';
6667
- lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
6668
6842
  }
6669
6843
  else {
6670
- const [resultValue, updatedChange, htmlIndex, plainTextSelectionEndIndex] = handleMentionTagUpdate(htmlText, oldPlainText, lastProcessedHTMLIndex, processedChange, tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength);
6671
- result += resultValue;
6672
- changeNewEndIndex = plainTextSelectionEndIndex;
6673
- processedChange = updatedChange;
6674
- lastProcessedHTMLIndex = htmlIndex;
6844
+ const updateMentionTagResult = handleMentionTagUpdate({
6845
+ htmlText,
6846
+ oldPlainText,
6847
+ lastProcessedHTMLIndex,
6848
+ processedChange,
6849
+ change,
6850
+ tag,
6851
+ closeTagIdx: closingTagInfo.closeTagIdx,
6852
+ closeTagLength: closingTagInfo.closeTagLength,
6853
+ plainTextEndIndex: closingTagInfo.plainTextEndIndex,
6854
+ startIndex,
6855
+ oldPlainTextEndIndex,
6856
+ mentionTagLength
6857
+ });
6858
+ result += updateMentionTagResult.result;
6859
+ changeNewEndIndex = updateMentionTagResult.plainTextSelectionEndIndex;
6860
+ processedChange = updateMentionTagResult.updatedChange;
6861
+ lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
6675
6862
  }
6676
- // the change is handled; exit
6677
- break;
6678
6863
  }
6679
- else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content) {
6864
+ else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
6680
6865
  // with subtags
6681
- // before the tag content
6682
6866
  const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length);
6683
- lastProcessedHTMLIndex = closeTagIdx;
6684
- const [content, updatedChangeNewEndIndex] = updateHTML(tag.content, oldPlainText, newPlainText, tag.subTags, startIndex - mentionTagLength, oldPlainTextEndIndex - mentionTagLength, processedChange, mentionTrigger);
6685
- result += stringBefore + content;
6686
- changeNewEndIndex = updatedChangeNewEndIndex;
6687
- break;
6867
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
6868
+ const updatedContent = updateHTML({
6869
+ htmlText: tag.content,
6870
+ oldPlainText,
6871
+ newPlainText,
6872
+ tags: tag.subTags,
6873
+ startIndex,
6874
+ oldPlainTextEndIndex,
6875
+ change: processedChange,
6876
+ mentionTrigger
6877
+ });
6878
+ result += stringBefore + updatedContent.updatedHTML;
6879
+ changeNewEndIndex = updatedContent.updatedSelectionIndex;
6688
6880
  }
6689
6881
  else {
6690
6882
  // no subtags
6691
- const startChangeDiff = startIndex - tag.plainTextBeginIndex - mentionTagLength;
6692
- const endChangeDiff = oldPlainTextEndIndex - tag.plainTextBeginIndex - mentionTagLength;
6883
+ const startChangeDiff = startIndex - tag.plainTextBeginIndex;
6693
6884
  result +=
6694
6885
  htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length + startChangeDiff) +
6695
6886
  processedChange;
6696
6887
  processedChange = '';
6697
- lastProcessedHTMLIndex = tag.openTagIdx + tag.openTagBody.length + endChangeDiff;
6698
- // the change is handled; exit
6699
- break;
6888
+ if (oldPlainTextEndIndex < closingTagInfo.plainTextEndIndex) {
6889
+ const endChangeDiff = oldPlainTextEndIndex - tag.plainTextBeginIndex;
6890
+ lastProcessedHTMLIndex = tag.openTagIdx + tag.openTagBody.length + endChangeDiff;
6891
+ }
6892
+ else if (oldPlainTextEndIndex === closingTagInfo.plainTextEndIndex) {
6893
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
6894
+ }
6700
6895
  }
6896
+ // the change is handled; exit
6897
+ break;
6701
6898
  }
6702
- else if (startIndex > tag.plainTextBeginIndex && oldPlainTextEndIndex > plainTextEndIndex) {
6703
- //the change started in the tag but finishes somewhere further
6899
+ else if (startIndex > tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
6900
+ // the change started in the tag but finishes somewhere further
6704
6901
  const startChangeDiff = startIndex - tag.plainTextBeginIndex - mentionTagLength;
6705
6902
  if (isMentionTag) {
6706
- const [resultValue, updatedChange, htmlIndex] = handleMentionTagUpdate(htmlText, oldPlainText, lastProcessedHTMLIndex, oldPlainText.substring(startIndex, startIndex + 1) !== ' ' && change === '' ? ' ' : '', // if substring !== ' ' && change is empty -> the change should be " " and not empty string but " " wasn't included in change; otherwise the part of mention should be just deleted without processedChange update
6707
- tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength);
6708
- result += resultValue;
6709
- lastProcessedHTMLIndex = htmlIndex;
6710
- processedChange = updatedChange;
6903
+ const updateMentionTagResult = handleMentionTagUpdate({
6904
+ htmlText,
6905
+ oldPlainText,
6906
+ lastProcessedHTMLIndex,
6907
+ processedChange: '',
6908
+ change,
6909
+ tag,
6910
+ closeTagIdx: closingTagInfo.closeTagIdx,
6911
+ closeTagLength: closingTagInfo.closeTagLength,
6912
+ plainTextEndIndex: closingTagInfo.plainTextEndIndex,
6913
+ startIndex,
6914
+ oldPlainTextEndIndex,
6915
+ mentionTagLength
6916
+ });
6917
+ result += updateMentionTagResult.result;
6918
+ lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
6711
6919
  // no need to handle plainTextSelectionEndIndex as the change will be added later
6712
- // proceed with the next calculations
6713
6920
  }
6714
6921
  else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
6715
6922
  // with subtags
6716
- // before the tag content
6717
6923
  const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length);
6718
- lastProcessedHTMLIndex = closeTagIdx;
6719
- const [content] = updateHTML(tag.content, oldPlainText, newPlainText, tag.subTags, startIndex - mentionTagLength, oldPlainTextEndIndex - mentionTagLength, '', // the part of the tag should be just deleted without processedChange update and change will be added after this tag
6720
- mentionTrigger);
6721
- result += stringBefore + content;
6722
- // proceed with the next calculations
6924
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
6925
+ const updatedContent = updateHTML({
6926
+ htmlText: tag.content,
6927
+ oldPlainText,
6928
+ newPlainText,
6929
+ tags: tag.subTags,
6930
+ startIndex,
6931
+ oldPlainTextEndIndex,
6932
+ change: '',
6933
+ mentionTrigger
6934
+ });
6935
+ result += stringBefore + updatedContent.updatedHTML;
6723
6936
  }
6724
6937
  else {
6725
6938
  // no subtags
6726
6939
  result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length + startChangeDiff);
6727
- lastProcessedHTMLIndex = closeTagIdx;
6728
- // proceed with the next calculations
6940
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
6729
6941
  }
6942
+ // proceed with the next calculations
6730
6943
  }
6731
- else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex > plainTextEndIndex) {
6944
+ else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
6732
6945
  // the change starts before the tag and finishes after it
6733
6946
  // tag should be removed, no matter if there are subtags
6734
6947
  // no need to save anything between lastProcessedHTMLIndex and closeTagIdx + closeTagLength
6735
- lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
6948
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
6736
6949
  // proceed with the next calculations
6737
6950
  }
6738
- else if (startIndex === tag.plainTextBeginIndex && oldPlainTextEndIndex > plainTextEndIndex) {
6951
+ else if (startIndex === tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
6739
6952
  // the change starts in the tag and finishes after it
6740
6953
  // tag should be removed, no matter if there are subtags
6741
6954
  result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx);
6742
6955
  // processedChange shouldn't be updated as it will be added after the tag
6743
- lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
6956
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
6744
6957
  // proceed with the next calculations
6745
6958
  }
6746
- else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex < plainTextEndIndex) {
6959
+ else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex < closingTagInfo.plainTextEndIndex) {
6747
6960
  // the change starts before the tag and ends in a tag
6748
6961
  if (isMentionTag) {
6749
- const [resultValue, , htmlIndex] = handleMentionTagUpdate(htmlText, oldPlainText, lastProcessedHTMLIndex, '', // the part of mention should be just deleted without processedChange update
6750
- tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength);
6751
- changeNewEndIndex = tag.plainTextBeginIndex;
6752
- result += resultValue;
6753
- lastProcessedHTMLIndex = htmlIndex;
6962
+ // mention tag
6963
+ const updateMentionTagResult = handleMentionTagUpdate({
6964
+ htmlText,
6965
+ oldPlainText,
6966
+ lastProcessedHTMLIndex,
6967
+ processedChange: '',
6968
+ change,
6969
+ tag,
6970
+ closeTagIdx: closingTagInfo.closeTagIdx,
6971
+ closeTagLength: closingTagInfo.closeTagLength,
6972
+ plainTextEndIndex: closingTagInfo.plainTextEndIndex,
6973
+ startIndex,
6974
+ oldPlainTextEndIndex,
6975
+ mentionTagLength
6976
+ });
6977
+ changeNewEndIndex = updateMentionTagResult.plainTextSelectionEndIndex;
6978
+ result += updateMentionTagResult.result;
6979
+ lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
6754
6980
  }
6755
6981
  else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
6756
6982
  // with subtags
6757
- // before the tag content
6758
6983
  const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length);
6759
- lastProcessedHTMLIndex = closeTagIdx;
6760
- const [content] = updateHTML(tag.content, oldPlainText, newPlainText, tag.subTags, startIndex - mentionTagLength, oldPlainTextEndIndex - mentionTagLength, processedChange, // processedChange should equal '' and the part of the tag should be deleted as the change was handled before this tag
6761
- mentionTrigger);
6762
- result += stringBefore + content;
6984
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
6985
+ const updatedContent = updateHTML({
6986
+ htmlText: tag.content,
6987
+ oldPlainText,
6988
+ newPlainText,
6989
+ tags: tag.subTags,
6990
+ startIndex,
6991
+ oldPlainTextEndIndex,
6992
+ change: processedChange,
6993
+ mentionTrigger
6994
+ });
6995
+ processedChange = '';
6996
+ result += stringBefore + updatedContent.updatedHTML;
6763
6997
  }
6764
6998
  else {
6765
6999
  // no subtags
@@ -6767,123 +7001,67 @@ const updateHTML = (htmlText, oldPlainText, newPlainText, tags, startIndex, oldP
6767
7001
  htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length) + processedChange;
6768
7002
  processedChange = '';
6769
7003
  // oldPlainTextEndIndex already includes mentionTag length
6770
- const endChangeDiff = plainTextEndIndex - oldPlainTextEndIndex;
7004
+ const endChangeDiff = closingTagInfo.plainTextEndIndex - oldPlainTextEndIndex;
6771
7005
  // as change may be before the end of the tag, we need to add the rest of the tag
6772
- lastProcessedHTMLIndex = closeTagIdx - endChangeDiff;
7006
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx - endChangeDiff;
6773
7007
  }
6774
7008
  // the change is handled; exit
6775
7009
  break;
6776
7010
  }
6777
- else if (startIndex > tag.plainTextBeginIndex && oldPlainTextEndIndex === plainTextEndIndex) {
6778
- // the change starts in the tag and ends at the end of a tag
6779
- if (isMentionTag) {
6780
- if (change !== '' && startIndex === plainTextEndIndex) {
6781
- // non empty change at the end of the mention tag to be added after the mention tag
6782
- result += htmlText.substring(lastProcessedHTMLIndex, closeTagIdx + closeTagLength) + processedChange;
6783
- changeNewEndIndex = plainTextEndIndex + processedChange.length;
6784
- processedChange = '';
6785
- lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
6786
- }
6787
- else if (change !== '') {
6788
- // mention tag should be deleted when user tries to edit it
6789
- result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx) + processedChange;
6790
- changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
6791
- processedChange = '';
6792
- lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
6793
- }
6794
- else {
6795
- const [resultValue, updatedChange, htmlIndex, plainTextSelectionEndIndex] = handleMentionTagUpdate(htmlText, oldPlainText, lastProcessedHTMLIndex, processedChange, tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength);
6796
- result += resultValue;
6797
- processedChange = updatedChange;
6798
- lastProcessedHTMLIndex = htmlIndex;
6799
- changeNewEndIndex = plainTextSelectionEndIndex;
6800
- }
6801
- // the change is handled; exit
6802
- break;
6803
- }
6804
- else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
6805
- // with subtags
6806
- // before the tag content
6807
- const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length);
6808
- lastProcessedHTMLIndex = closeTagIdx;
6809
- const [content, updatedChangeNewEndIndex] = updateHTML(tag.content, oldPlainText, newPlainText, tag.subTags, startIndex - mentionTagLength, oldPlainTextEndIndex - mentionTagLength, processedChange, mentionTrigger);
6810
- result += stringBefore + content;
6811
- changeNewEndIndex = updatedChangeNewEndIndex;
6812
- break;
6813
- }
6814
- else {
6815
- // no subtags
6816
- const startChangeDiff = startIndex - tag.plainTextBeginIndex - mentionTagLength;
6817
- result +=
6818
- htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length + startChangeDiff) +
6819
- processedChange;
6820
- processedChange = '';
6821
- lastProcessedHTMLIndex = closeTagIdx;
6822
- // the change is handled; exit
6823
- break;
6824
- }
6825
- }
6826
- lastProcessedPlainTextTagEndIndex = plainTextEndIndex;
7011
+ lastProcessedPlainTextTagEndIndex = closingTagInfo.plainTextEndIndex;
6827
7012
  }
6828
- if (i === tags.length - 1 && oldPlainTextEndIndex >= plainTextEndIndex) {
7013
+ if (i === tags.length - 1 && oldPlainTextEndIndex >= closingTagInfo.plainTextEndIndex) {
6829
7014
  // the last tag should handle the end of the change if needed
6830
7015
  // oldPlainTextEndIndex already includes mentionTag length
6831
- const endChangeDiff = oldPlainTextEndIndex - plainTextEndIndex;
6832
- if (startIndex >= plainTextEndIndex) {
6833
- const startChangeDiff = startIndex - plainTextEndIndex;
7016
+ const endChangeDiff = oldPlainTextEndIndex - closingTagInfo.plainTextEndIndex;
7017
+ if (startIndex >= closingTagInfo.plainTextEndIndex) {
7018
+ const startChangeDiff = startIndex - closingTagInfo.plainTextEndIndex;
6834
7019
  result +=
6835
- htmlText.substring(lastProcessedHTMLIndex, closeTagIdx + closeTagLength + startChangeDiff) + processedChange;
7020
+ htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength + startChangeDiff) + processedChange;
6836
7021
  }
6837
7022
  else {
6838
- result += htmlText.substring(lastProcessedHTMLIndex, closeTagIdx + closeTagLength) + processedChange;
7023
+ result +=
7024
+ htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength) +
7025
+ processedChange;
6839
7026
  }
6840
7027
  processedChange = '';
6841
- lastProcessedHTMLIndex = closeTagIdx + closeTagLength + endChangeDiff;
7028
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength + endChangeDiff;
6842
7029
  // the change is handled; exit
6843
7030
  // break is not required here as this is the last element but added for consistency
6844
7031
  break;
6845
7032
  }
6846
7033
  }
6847
7034
  if (lastProcessedHTMLIndex < htmlText.length) {
7035
+ // add the rest of the html string
6848
7036
  result += htmlText.substring(lastProcessedHTMLIndex);
6849
7037
  }
6850
- return [result, changeNewEndIndex];
7038
+ return { updatedHTML: result, updatedSelectionIndex: changeNewEndIndex };
6851
7039
  };
6852
7040
  /* @conditional-compile-remove(mention) */
6853
7041
  /**
6854
7042
  * Given the oldText and newText, find the start index, old end index and new end index for the changes
6855
7043
  *
6856
- * @param oldText - the old text
6857
- * @param newText - the new text
6858
- * @param selectionEnd - the end of the selection
6859
- * @returns change start index, old end index and new end index. The old and new end indexes are exclusive.
6860
7044
  * @private
7045
+ * @param props - Props for finding stings diff indexes function.
7046
+ * @returns Indexes for change start and ends in new and old texts. The old and new end indexes are exclusive.
6861
7047
  */
6862
- const findStringsDiffIndexes = (oldText, newText, selectionEnd // should be a valid position in the input field
6863
- ) => {
7048
+ const findStringsDiffIndexes = (props) => {
7049
+ const { oldText, newText, previousSelectionStart, previousSelectionEnd, currentSelectionStart, currentSelectionEnd } = props;
6864
7050
  const newTextLength = newText.length;
6865
7051
  const oldTextLength = oldText.length;
6866
- let changeStart = 0;
7052
+ // let changeStart = 0;
6867
7053
  let newChangeEnd = newTextLength;
6868
7054
  let oldChangeEnd = oldTextLength;
6869
- const length = Math.min(newTextLength, oldTextLength, selectionEnd);
6870
- for (let i = 0; i < length; i++) {
6871
- if (newText[i] !== oldText[i]) {
6872
- // the symbol with changeStart index is updated
6873
- changeStart = i;
6874
- break;
6875
- }
6876
- else if (i === length - 1 && newText[i] === oldText[i]) {
6877
- // the symbol is added at the end of inputTextValue
6878
- changeStart = length;
6879
- break;
6880
- }
6881
- }
7055
+ const previousSelectionStartValue = previousSelectionStart > -1 ? previousSelectionStart : oldTextLength;
7056
+ const previousSelectionEndValue = previousSelectionEnd > -1 ? previousSelectionEnd : oldTextLength;
7057
+ const currentSelectionStartValue = currentSelectionStart > -1 ? currentSelectionStart : newTextLength;
7058
+ const currentSelectionEndValue = currentSelectionEnd > -1 ? currentSelectionEnd : newTextLength;
7059
+ const changeStart = Math.min(previousSelectionStartValue, previousSelectionEndValue, currentSelectionStartValue, currentSelectionEndValue, newTextLength, oldTextLength);
6882
7060
  if (oldTextLength < newTextLength) {
6883
7061
  //insert or replacement
6884
7062
  if (oldTextLength === changeStart) {
6885
7063
  // when change was at the end of string
6886
- // Change is found
7064
+ // change is found
6887
7065
  newChangeEnd = newTextLength;
6888
7066
  oldChangeEnd = oldTextLength;
6889
7067
  }
@@ -6892,7 +7070,7 @@ const findStringsDiffIndexes = (oldText, newText, selectionEnd // should be a va
6892
7070
  newChangeEnd = newTextLength - i - 1;
6893
7071
  oldChangeEnd = oldTextLength - i - 1;
6894
7072
  if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
6895
- // Change is found
7073
+ // change is found
6896
7074
  break;
6897
7075
  }
6898
7076
  }
@@ -6905,7 +7083,7 @@ const findStringsDiffIndexes = (oldText, newText, selectionEnd // should be a va
6905
7083
  //deletion or replacement
6906
7084
  if (newTextLength === changeStart) {
6907
7085
  // when change was at the end of string
6908
- // Change is found
7086
+ // change is found
6909
7087
  newChangeEnd = newTextLength;
6910
7088
  oldChangeEnd = oldTextLength;
6911
7089
  }
@@ -6914,7 +7092,7 @@ const findStringsDiffIndexes = (oldText, newText, selectionEnd // should be a va
6914
7092
  newChangeEnd = newTextLength - i - 1;
6915
7093
  oldChangeEnd = oldTextLength - i - 1;
6916
7094
  if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
6917
- // Change is found
7095
+ // change is found
6918
7096
  break;
6919
7097
  }
6920
7098
  }
@@ -6924,12 +7102,12 @@ const findStringsDiffIndexes = (oldText, newText, selectionEnd // should be a va
6924
7102
  }
6925
7103
  }
6926
7104
  else {
6927
- //replacement
7105
+ // replacement
6928
7106
  for (let i = 1; i < oldTextLength && oldTextLength - i >= changeStart; i++) {
6929
7107
  newChangeEnd = newTextLength - i - 1;
6930
7108
  oldChangeEnd = oldTextLength - i - 1;
6931
7109
  if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
6932
- // Change is found
7110
+ // change is found
6933
7111
  break;
6934
7112
  }
6935
7113
  }
@@ -6944,13 +7122,30 @@ const findStringsDiffIndexes = (oldText, newText, selectionEnd // should be a va
6944
7122
  return { changeStart, oldChangeEnd, newChangeEnd };
6945
7123
  };
6946
7124
  /* @conditional-compile-remove(mention) */
7125
+ /**
7126
+ * Get the html string for the mention suggestion.
7127
+ *
7128
+ * @private
7129
+ * @param suggestion - The mention suggestion.
7130
+ * @param localeStrings - The locale strings.
7131
+ * @returns The html string for the mention suggestion.
7132
+ */
6947
7133
  const htmlStringForMentionSuggestion = (suggestion, localeStrings) => {
6948
7134
  const idHTML = ' id ="' + suggestion.id + '"';
6949
7135
  const displayTextHTML = ' displayText ="' + suggestion.displayText + '"';
6950
7136
  const displayText = getDisplayNameForMentionSuggestion(suggestion, localeStrings);
6951
- return '<msft-mention' + idHTML + displayTextHTML + '>' + displayText + '</msft-mention>';
7137
+ return '<' + MSFT_MENTION_TAG + idHTML + displayTextHTML + '>' + displayText + '</' + MSFT_MENTION_TAG + '>';
6952
7138
  };
6953
7139
  /* @conditional-compile-remove(mention) */
7140
+ /**
7141
+ * Get display name for the mention suggestion.
7142
+ *
7143
+ * @private
7144
+ *
7145
+ * @param suggestion - The mention suggestion.
7146
+ * @param localeStrings - The locale strings.
7147
+ * @returns The display name for the mention suggestion or display name placeholder if display name is empty.
7148
+ */
6954
7149
  const getDisplayNameForMentionSuggestion = (suggestion, localeStrings) => {
6955
7150
  const displayNamePlaceholder = localeStrings.participantItem.displayNamePlaceholder;
6956
7151
  return suggestion.displayText !== '' ? suggestion.displayText : displayNamePlaceholder !== null && displayNamePlaceholder !== void 0 ? displayNamePlaceholder : '';
@@ -6958,8 +7153,9 @@ const getDisplayNameForMentionSuggestion = (suggestion, localeStrings) => {
6958
7153
  /* @conditional-compile-remove(mention) */
6959
7154
  /**
6960
7155
  * Parse the text and return the tags and the plain text in one go
7156
+ * @private
6961
7157
  * @param text - The text to parse for HTML tags
6962
- * @param trigger The trigger to show for the msft-mention tag in plain text
7158
+ * @param trigger The trigger to show for the mention tag in plain text
6963
7159
  *
6964
7160
  * @returns An array of tags and the plain text representation
6965
7161
  */
@@ -7003,7 +7199,7 @@ const textToTagParser = (text, trigger) => {
7003
7199
  // Tag startIdx is absolute to the text. This is updated later to be relative to the parent tag
7004
7200
  currentOpenTag.content = text.substring(currentOpenTag.openTagIdx + currentOpenTag.openTagBody.length, foundHtmlTag.startIdx);
7005
7201
  // Insert the plain text pieces for the sub tags
7006
- if (currentOpenTag.tagType === 'msft-mention') {
7202
+ if (currentOpenTag.tagType === MSFT_MENTION_TAG) {
7007
7203
  plainTextRepresentation =
7008
7204
  plainTextRepresentation.slice(0, currentOpenTag.plainTextBeginIndex) +
7009
7205
  trigger +
@@ -7033,7 +7229,7 @@ const textToTagParser = (text, trigger) => {
7033
7229
  // Update parsing index; move past the end of the close tag
7034
7230
  parseIndex = foundHtmlTag.startIdx + foundHtmlTag.content.length;
7035
7231
  } // While parseIndex < text.length loop
7036
- return [tags, plainTextRepresentation];
7232
+ return { tags, plainText: plainTextRepresentation };
7037
7233
  };
7038
7234
  /* @conditional-compile-remove(mention) */
7039
7235
  const parseOpenTag = (tag, startIdx) => {
@@ -13554,6 +13750,7 @@ const CameraButton = (props) => {
13554
13750
  if (props.onShowVideoEffectsPicker) {
13555
13751
  splitButtonMenuItems.push({
13556
13752
  key: 'effects',
13753
+ 'data-ui-id': 'camera-split-button-video-effects',
13557
13754
  text: strings.videoEffectsMenuItemTitle,
13558
13755
  iconProps: { iconName: 'OptionsVideoBackgroundEffect', styles: { root: { lineHeight: 0 } } },
13559
13756
  onClick: () => {
@@ -13572,11 +13769,12 @@ const CameraButton = (props) => {
13572
13769
  items: splitButtonMenuItems
13573
13770
  }
13574
13771
  };
13772
+ const splitButtonMenuProps = React.useMemo(() => (Object.assign(Object.assign({}, props.splitButtonMenuProps), { className: 'camera-split-button' })), [props.splitButtonMenuProps]);
13575
13773
  return (React__default['default'].createElement(React__default['default'].Fragment, null,
13576
13774
  React__default['default'].createElement(Announcer, { announcementString: announcerString, ariaLive: 'polite' }),
13577
13775
  React__default['default'].createElement(ControlBarButton, Object.assign({}, props, { disabled: disabled, onClick: onToggleCamera ? onToggleClick : props.onClick, onRenderOnIcon: (_a = props.onRenderOnIcon) !== null && _a !== void 0 ? _a : onRenderCameraOnIcon, onRenderOffIcon: (_b = props.onRenderOffIcon) !== null && _b !== void 0 ? _b : onRenderCameraOffIcon, strings: strings, labelKey: (_c = props.labelKey) !== null && _c !== void 0 ? _c : 'cameraButtonLabel', menuProps: (_d = props.menuProps) !== null && _d !== void 0 ? _d : (props.enableDeviceSelectionMenu
13578
13776
  ? generateDefaultDeviceMenuProps(Object.assign(Object.assign({}, props), { styles: (_e = props.styles) === null || _e === void 0 ? void 0 : _e.menuStyles }), strings, splitButtonPrimaryAction)
13579
- : undefined), menuIconProps: ((_f = props.menuIconProps) !== null && _f !== void 0 ? _f : !props.enableDeviceSelectionMenu) ? { hidden: true } : undefined, split: (_g = props.split) !== null && _g !== void 0 ? _g : props.enableDeviceSelectionMenu, "aria-roledescription": props.enableDeviceSelectionMenu ? strings.cameraButtonSplitRoleDescription : undefined, splitButtonAriaLabel: props.enableDeviceSelectionMenu ? splitButtonAriaString : undefined }))));
13777
+ : undefined), menuIconProps: ((_f = props.menuIconProps) !== null && _f !== void 0 ? _f : !props.enableDeviceSelectionMenu) ? { hidden: true } : undefined, split: (_g = props.split) !== null && _g !== void 0 ? _g : props.enableDeviceSelectionMenu, "aria-roledescription": props.enableDeviceSelectionMenu ? strings.cameraButtonSplitRoleDescription : undefined, splitButtonAriaLabel: props.enableDeviceSelectionMenu ? splitButtonAriaString : undefined, splitButtonMenuProps: splitButtonMenuProps }))));
13580
13778
  };
13581
13779
 
13582
13780
  // Copyright (c) Microsoft Corporation.
@@ -15078,7 +15276,7 @@ const _VideoEffectsItem = (props) => {
15078
15276
  backgroundSize
15079
15277
  }), [backgroundImage, disabled, isSelected, theme]);
15080
15278
  return (React__default['default'].createElement(react.TooltipHost, Object.assign({}, props.tooltipProps),
15081
- React__default['default'].createElement(react.Stack, { key: props.key, className: react.mergeStyles((_d = props.styles) === null || _d === void 0 ? void 0 : _d.root), verticalAlign: "center", horizontalAlign: "center", styles: containerStyles, onClick: disabled ? undefined : () => { var _a; return (_a = props.onSelect) === null || _a === void 0 ? void 0 : _a.call(props, props.key); }, onKeyDown: disabled
15279
+ React__default['default'].createElement(react.Stack, { key: props.key, className: react.mergeStyles((_d = props.styles) === null || _d === void 0 ? void 0 : _d.root), verticalAlign: "center", horizontalAlign: "center", styles: containerStyles, "data-ui-id": `video-effects-item`, onClick: disabled ? undefined : () => { var _a; return (_a = props.onSelect) === null || _a === void 0 ? void 0 : _a.call(props, props.key); }, onKeyDown: disabled
15082
15280
  ? undefined
15083
15281
  : (e) => {
15084
15282
  var _a;
@@ -19071,6 +19269,10 @@ class AzureCommunicationChatAdapter {
19071
19269
  });
19072
19270
  }
19073
19271
  messageReceivedListener(event) {
19272
+ const isCurrentChatAdapterThread = event.threadId === this.chatThreadClient.threadId;
19273
+ if (!isCurrentChatAdapterThread) {
19274
+ return;
19275
+ }
19074
19276
  const message = convertEventToChatMessage(event);
19075
19277
  this.emitter.emit('messageReceived', { message });
19076
19278
  const currentUserId = toFlatCommunicationIdentifier(this.chatClient.getState().userId);
@@ -21587,7 +21789,9 @@ const CommonCallControlBar = (props) => {
21587
21789
  !props.mobileView && sideButtonsPresent && (React__default['default'].createElement(react.Stack.Item, null,
21588
21790
  React__default['default'].createElement("div", { ref: sidepaneControlsRef },
21589
21791
  React__default['default'].createElement(react.Stack, { horizontal: true, className: !props.mobileView ? react.mergeStyles(desktopButtonContainerStyle) : undefined },
21590
- isEnabled$1(options === null || options === void 0 ? void 0 : options.peopleButton) && (React__default['default'].createElement(PeopleButton, { checked: props.peopleButtonChecked, ariaLabel: peopleButtonStrings === null || peopleButtonStrings === void 0 ? void 0 : peopleButtonStrings.label, showLabel: options.displayType !== 'compact', onClick: props.onPeopleButtonClicked, "data-ui-id": "common-call-composite-people-button", disabled: props.disableButtonsForLobbyPage || isDisabled$2(options.peopleButton), strings: peopleButtonStrings, styles: commonButtonStyles })), (_b = customButtons['secondary']) === null || _b === void 0 ? void 0 :
21792
+ isEnabled$1(options === null || options === void 0 ? void 0 : options.peopleButton) && (React__default['default'].createElement(PeopleButton, { checked: props.peopleButtonChecked, ariaLabel: peopleButtonStrings === null || peopleButtonStrings === void 0 ? void 0 : peopleButtonStrings.label, showLabel: options.displayType !== 'compact', onClick: props.onPeopleButtonClicked, "data-ui-id": "common-call-composite-people-button", disabled: props.disableButtonsForLobbyPage ||
21793
+ props.disableButtonsForHoldScreen ||
21794
+ isDisabled$2(options.peopleButton), strings: peopleButtonStrings, styles: commonButtonStyles })), (_b = customButtons['secondary']) === null || _b === void 0 ? void 0 :
21591
21795
  _b.slice(0, CUSTOM_BUTTON_OPTIONS.MAX_SECONDARY_DESKTOP_CUSTOM_BUTTONS).map((CustomButton, i) => {
21592
21796
  return (React__default['default'].createElement(CustomButton, { key: `secondary-custom-button-${i}`, styles: commonButtonStyles, showLabel: options.displayType !== 'compact' }));
21593
21797
  }))))))));
@@ -22028,7 +22232,7 @@ const MoreDrawer = (props) => {
22028
22232
  text: props.strings.peopleButtonLabel,
22029
22233
  iconProps: { iconName: 'MoreDrawerPeople' },
22030
22234
  onItemClick: props.onPeopleButtonClicked,
22031
- disabled: isDisabled$2(drawerSelectionOptions.peopleButton)
22235
+ disabled: isDisabled$2(drawerSelectionOptions.peopleButton) || props.disableButtonsForHoldScreen
22032
22236
  });
22033
22237
  }
22034
22238
  /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
@@ -23327,14 +23531,22 @@ const CallArrangement = (props) => {
23327
23531
  const containerWidth = _useContainerWidth(containerRef);
23328
23532
  const containerHeight = _useContainerHeight(containerRef);
23329
23533
  const isInLobby = _isInLobbyOrConnecting(useSelector$1(callStatusSelector).callStatus);
23534
+ const { updateSidePaneRenderer } = props;
23330
23535
  /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
23331
23536
  const isInLocalHold = useSelector$1(getPage) === 'hold';
23537
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
23538
+ React.useEffect(() => {
23539
+ if (isInLocalHold) {
23540
+ // close side pane on local hold
23541
+ updateSidePaneRenderer(undefined);
23542
+ }
23543
+ }, [updateSidePaneRenderer, isInLocalHold]);
23332
23544
  const adapter = useAdapter();
23333
23545
  const [drawerMenuItems, setDrawerMenuItems] = React.useState([]);
23334
23546
  const peoplePaneProps = React.useMemo(() => {
23335
23547
  var _a;
23336
23548
  return ({
23337
- updateSidePaneRenderer: props.updateSidePaneRenderer,
23549
+ updateSidePaneRenderer,
23338
23550
  setDrawerMenuItems,
23339
23551
  inviteLink: props.callControlProps.callInvitationURL,
23340
23552
  /* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
@@ -23343,7 +23555,7 @@ const CallArrangement = (props) => {
23343
23555
  mobileView: props.mobileView
23344
23556
  });
23345
23557
  }, [
23346
- props.updateSidePaneRenderer,
23558
+ updateSidePaneRenderer,
23347
23559
  props.callControlProps.callInvitationURL,
23348
23560
  (_a = props.callControlProps) === null || _a === void 0 ? void 0 : _a.onFetchParticipantMenuItems,
23349
23561
  /* @conditional-compile-remove(one-to-n-calling) @conditional-compile-remove(PSTN-calls) */
@@ -24865,7 +25077,7 @@ const ConfigurationPage = (props) => {
24865
25077
  title,
24866
25078
  callDescription),
24867
25079
  /* @conditional-compile-remove(video-background-effects) */
24868
- React__default['default'].createElement(react.DefaultButton, { iconProps: { iconName: 'OptionsVideoBackgroundEffect' }, styles: effectsButtonStyles(theme), onClick: toggleVideoEffectsPane }, locale.strings.call.configurationPageVideoEffectsButtonLabel),
25080
+ React__default['default'].createElement(react.DefaultButton, { iconProps: { iconName: 'OptionsVideoBackgroundEffect' }, styles: effectsButtonStyles(theme), onClick: toggleVideoEffectsPane, "data-ui-id": 'call-config-video-effects-button' }, locale.strings.call.configurationPageVideoEffectsButtonLabel),
24869
25081
  React__default['default'].createElement(LocalDeviceSettings, Object.assign({}, options, localDeviceSettingsHandlers, { cameraPermissionGranted: cameraPermissionGrantedTrampoline(cameraPermissionGranted,
24870
25082
  /* @conditional-compile-remove(call-readiness) */ videoState), microphonePermissionGranted: micPermissionGrantedTrampoline(microphonePermissionGranted,
24871
25083
  /* @conditional-compile-remove(call-readiness) */ audioState),
@@ -27082,6 +27294,12 @@ const CallWithChatScreen = (props) => {
27082
27294
  clearInterval(chatFocusTimeout);
27083
27295
  }, 300);
27084
27296
  }, [compositeParentDivId]);
27297
+ const isOnHold = isOnHoldTrampoline(currentPage);
27298
+ React.useEffect(() => {
27299
+ if (isOnHold) {
27300
+ closeChat();
27301
+ }
27302
+ }, [closeChat, isOnHold]);
27085
27303
  const hasJoinedCall = !!(currentPage && hasJoinedCallFn(currentPage, currentCallState !== null && currentCallState !== void 0 ? currentCallState : 'None'));
27086
27304
  const toggleChat = React.useCallback(() => {
27087
27305
  isChatOpen || !hasJoinedCall ? closeChat() : openChat();
@@ -27095,7 +27313,7 @@ const CallWithChatScreen = (props) => {
27095
27313
  const theme = useTheme();
27096
27314
  const commonButtonStyles = React.useMemo(() => (!mobileView ? getDesktopCommonButtonStyles(theme) : undefined), [mobileView, theme]);
27097
27315
  const showChatButton = checkShowChatButton(props.callControls);
27098
- const chatButtonDisabled = showChatButton && (checkChatButtonIsDisabled(props.callControls) || !hasJoinedCall);
27316
+ const chatButtonDisabled = showChatButton && (checkChatButtonIsDisabled(props.callControls) || !hasJoinedCall || isOnHold);
27099
27317
  const chatTabHeaderProps = React.useMemo(() => mobileView && showChatButton
27100
27318
  ? {
27101
27319
  onClick: toggleChat,
@@ -27223,6 +27441,10 @@ const checkShowChatButton = (callControls) => {
27223
27441
  const checkChatButtonIsDisabled = (callControls) => {
27224
27442
  return typeof callControls === 'object' && isDisabled$2(callControls === null || callControls === void 0 ? void 0 : callControls.chatButton);
27225
27443
  };
27444
+ const isOnHoldTrampoline = (page) => {
27445
+ /* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(one-to-n-calling) */
27446
+ return page === 'hold';
27447
+ };
27226
27448
 
27227
27449
  // Copyright (c) Microsoft Corporation.
27228
27450
  // Licensed under the MIT license.