@azure/communication-react 1.5.1-alpha-202305040013 → 1.5.1-alpha-202305060013

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 (68) hide show
  1. package/dist/communication-react.d.ts +84 -67
  2. package/dist/dist-cjs/communication-react/index.js +1460 -185
  3. package/dist/dist-cjs/communication-react/index.js.map +1 -1
  4. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js +1 -1
  5. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js.map +1 -1
  6. package/dist/dist-esm/communication-react/src/index.d.ts +1 -1
  7. package/dist/dist-esm/communication-react/src/index.js.map +1 -1
  8. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponent.d.ts +3 -3
  9. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponent.js +7 -2
  10. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponent.js.map +1 -1
  11. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentAsEditBox.d.ts +2 -0
  12. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentAsEditBox.js +5 -1
  13. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentAsEditBox.js.map +1 -1
  14. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentAsMessageBubble.d.ts +4 -4
  15. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentAsMessageBubble.js +3 -1
  16. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentAsMessageBubble.js.map +1 -1
  17. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageContent.d.ts +2 -2
  18. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageContent.js +56 -35
  19. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageContent.js.map +1 -1
  20. package/dist/dist-esm/react-components/src/components/ChatMessage/MentionRenderer.d.ts +10 -0
  21. package/dist/dist-esm/react-components/src/components/ChatMessage/MentionRenderer.js +15 -0
  22. package/dist/dist-esm/react-components/src/components/ChatMessage/MentionRenderer.js.map +1 -0
  23. package/dist/dist-esm/react-components/src/components/InputBoxComponent.d.ts +3 -3
  24. package/dist/dist-esm/react-components/src/components/InputBoxComponent.js +1038 -5
  25. package/dist/dist-esm/react-components/src/components/InputBoxComponent.js.map +1 -1
  26. package/dist/dist-esm/react-components/src/components/MentionPopover.d.ts +121 -0
  27. package/dist/dist-esm/react-components/src/components/MentionPopover.js +125 -0
  28. package/dist/dist-esm/react-components/src/components/MentionPopover.js.map +1 -0
  29. package/dist/dist-esm/react-components/src/components/MessageThread.d.ts +4 -4
  30. package/dist/dist-esm/react-components/src/components/MessageThread.js +9 -3
  31. package/dist/dist-esm/react-components/src/components/MessageThread.js.map +1 -1
  32. package/dist/dist-esm/react-components/src/components/SendBox.d.ts +7 -7
  33. package/dist/dist-esm/react-components/src/components/SendBox.js +15 -9
  34. package/dist/dist-esm/react-components/src/components/SendBox.js.map +1 -1
  35. package/dist/dist-esm/react-components/src/components/index.d.ts +2 -2
  36. package/dist/dist-esm/react-components/src/components/index.js +2 -2
  37. package/dist/dist-esm/react-components/src/components/index.js.map +1 -1
  38. package/dist/dist-esm/react-components/src/components/styles/{AtMentionFlyout.style.d.ts → MentionPopover.style.d.ts} +4 -4
  39. package/dist/dist-esm/react-components/src/components/styles/{AtMentionFlyout.style.js → MentionPopover.style.js} +11 -13
  40. package/dist/dist-esm/react-components/src/components/styles/MentionPopover.style.js.map +1 -0
  41. package/dist/dist-esm/react-components/src/components/styles/MessageThread.styles.js +5 -1
  42. package/dist/dist-esm/react-components/src/components/styles/MessageThread.styles.js.map +1 -1
  43. package/dist/dist-esm/react-components/src/identifiers/IdentifierProvider.d.ts +4 -4
  44. package/dist/dist-esm/react-components/src/identifiers/IdentifierProvider.js +4 -4
  45. package/dist/dist-esm/react-components/src/identifiers/IdentifierProvider.js.map +1 -1
  46. package/dist/dist-esm/react-components/src/localization/LocalizationProvider.d.ts +3 -0
  47. package/dist/dist-esm/react-components/src/localization/LocalizationProvider.js.map +1 -1
  48. package/dist/dist-esm/react-components/src/localization/locales/en-US/strings.json +3 -0
  49. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/CallArrangement.js +8 -1
  50. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/CallArrangement.js.map +1 -1
  51. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/SidePane/useVideoEffectsPane.js +26 -3
  52. package/dist/dist-esm/react-composites/src/composites/CallComposite/components/SidePane/useVideoEffectsPane.js.map +1 -1
  53. package/dist/dist-esm/react-composites/src/composites/CallComposite/pages/ConfigurationPage.js +6 -0
  54. package/dist/dist-esm/react-composites/src/composites/CallComposite/pages/ConfigurationPage.js.map +1 -1
  55. package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/videoBackgroundErrorsSelector.d.ts +1 -1
  56. package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/videoBackgroundErrorsSelector.js +1 -1
  57. package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/videoBackgroundErrorsSelector.js.map +1 -1
  58. package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.d.ts +12 -0
  59. package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.js +13 -0
  60. package/dist/dist-esm/react-composites/src/composites/CallComposite/utils/Utils.js.map +1 -1
  61. package/dist/dist-esm/react-composites/src/composites/common/VideoEffectsPane.d.ts +5 -1
  62. package/dist/dist-esm/react-composites/src/composites/common/VideoEffectsPane.js +5 -24
  63. package/dist/dist-esm/react-composites/src/composites/common/VideoEffectsPane.js.map +1 -1
  64. package/package.json +13 -11
  65. package/dist/dist-esm/react-components/src/components/AtMentionFlyout.d.ts +0 -91
  66. package/dist/dist-esm/react-components/src/components/AtMentionFlyout.js +0 -58
  67. package/dist/dist-esm/react-components/src/components/AtMentionFlyout.js.map +0 -1
  68. package/dist/dist-esm/react-components/src/components/styles/AtMentionFlyout.style.js.map +0 -1
@@ -1,15 +1,83 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT license.
3
- import React, { useState, useCallback } from 'react';
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ import React, { useState, useCallback, useRef } from 'react';
13
+ /* @conditional-compile-remove(mention) */
14
+ import { useEffect } from 'react';
15
+ /* @conditional-compile-remove(mention) */
16
+ import { useLocale } from '../localization';
4
17
  import { Stack, TextField, mergeStyles, concatStyleSets, IconButton, TooltipHost } from '@fluentui/react';
5
18
  import { inputBoxStyle, inputBoxWrapperStyle, inputButtonStyle, textFieldStyle, textContainerStyle, inlineButtonsContainerStyle, newLineButtonsContainerStyle, inputBoxNewLineSpaceAffordance, inputButtonTooltipStyle } from './styles/InputBoxComponent.style';
19
+ /* @conditional-compile-remove(mention) */
20
+ import { Caret } from 'textarea-caret-ts';
6
21
  import { isDarkThemed } from '../theming/themeUtils';
7
22
  import { useTheme } from '../theming';
23
+ /* @conditional-compile-remove(mention) */
24
+ import { _MentionPopover } from './MentionPopover';
25
+ /* @conditional-compile-remove(mention) */
26
+ import { useDebouncedCallback } from 'use-debounce';
27
+ /* @conditional-compile-remove(mention) */
28
+ const defaultMentionTrigger = '@';
8
29
  /**
9
30
  * @private
10
31
  */
11
32
  export const InputBoxComponent = (props) => {
12
- const { styles, id, 'data-ui-id': dataUiId, textValue, onChange, textFieldRef, placeholderText, onKeyDown, onEnterKeyDown, supportNewline, inputClassName, errorMessage, disabled, children } = props;
33
+ const { styles, id, 'data-ui-id': dataUiId, textValue, onChange, textFieldRef, placeholderText, onKeyDown, onEnterKeyDown, supportNewline, inputClassName, errorMessage, disabled, children,
34
+ /* @conditional-compile-remove(mention) */
35
+ mentionLookupOptions } = props;
36
+ const inputBoxRef = useRef(null);
37
+ /* @conditional-compile-remove(mention) */
38
+ // Current suggestion list, provided by the callback
39
+ const [mentionSuggestions, setMentionSuggestions] = useState([]);
40
+ /* @conditional-compile-remove(mention) */
41
+ // Current suggestion list, provided by the callback
42
+ const [activeSuggestionIndex, setActiveSuggestionIndex] = useState(undefined);
43
+ /* @conditional-compile-remove(mention) */
44
+ // Index of the current trigger character in the text field
45
+ const [currentTriggerStartIndex, setCurrentTriggerStartIndex] = useState(-1);
46
+ /* @conditional-compile-remove(mention) */
47
+ const [inputTextValue, setInputTextValue] = useState('');
48
+ /* @conditional-compile-remove(mention) */
49
+ const [tagsValue, setTagsValue] = useState([]);
50
+ /* @conditional-compile-remove(mention) */
51
+ const [selectionStartValue, setSelectionStartValue] = useState(null);
52
+ /* @conditional-compile-remove(mention) */
53
+ const [selectionEndValue, setSelectionEndValue] = useState(null);
54
+ /* @conditional-compile-remove(mention) */
55
+ const [shouldHandleOnMouseDownDuringSelect, setShouldHandleOnMouseDownDuringSelect] = useState(true);
56
+ /* @conditional-compile-remove(mention) */
57
+ // Caret position in the text field
58
+ const [caretPosition, setCaretPosition] = useState(undefined);
59
+ /* @conditional-compile-remove(mention) */
60
+ // Index of where the caret is in the text field
61
+ const [caretIndex, setCaretIndex] = useState(undefined);
62
+ /* @conditional-compile-remove(mention) */
63
+ const localeStrings = useLocale().strings;
64
+ /* @conditional-compile-remove(mention) */
65
+ const updateMentionSuggestions = useCallback((suggestions) => {
66
+ var _a;
67
+ setMentionSuggestions(suggestions);
68
+ if (caretIndex !== undefined) {
69
+ (_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.setSelectionEnd(caretIndex);
70
+ }
71
+ }, [textFieldRef, caretIndex]);
72
+ /* @conditional-compile-remove(mention) */
73
+ // Parse the text and get the plain text version to display in the input box
74
+ useEffect(() => {
75
+ const trigger = (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) || defaultMentionTrigger;
76
+ const [tags, plainText] = textToTagParser(textValue, trigger);
77
+ setInputTextValue(plainText);
78
+ setTagsValue(tags);
79
+ updateMentionSuggestions([]);
80
+ }, [textValue, mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger, updateMentionSuggestions]);
13
81
  const mergedRootStyle = mergeStyles(inputBoxWrapperStyle, styles === null || styles === void 0 ? void 0 : styles.root);
14
82
  const mergedTextFiledStyle = mergeStyles(inputBoxStyle, inputClassName, props.inlineChildren ? {} : inputBoxNewLineSpaceAffordance);
15
83
  const mergedTextContainerStyle = mergeStyles(textContainerStyle, styles === null || styles === void 0 ? void 0 : styles.textFieldContainer);
@@ -17,20 +85,309 @@ export const InputBoxComponent = (props) => {
17
85
  fieldGroup: styles === null || styles === void 0 ? void 0 : styles.textField,
18
86
  errorMessage: styles === null || styles === void 0 ? void 0 : styles.systemMessage
19
87
  });
20
- const onTexFieldKeyDown = useCallback((ev) => {
88
+ /* @conditional-compile-remove(mention) */
89
+ const onSuggestionSelected = useCallback((suggestion) => {
90
+ var _a, _b;
91
+ let selectionEnd = ((_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.selectionEnd) || -1;
92
+ if (selectionEnd < 0) {
93
+ selectionEnd = 0;
94
+ }
95
+ else if (selectionEnd > inputTextValue.length) {
96
+ selectionEnd = inputTextValue.length;
97
+ }
98
+ const oldPlainText = inputTextValue;
99
+ const mention = htmlStringForMentionSuggestion(suggestion, localeStrings);
100
+ // update plain text with the mention html text
101
+ const newPlainText = inputTextValue.substring(0, currentTriggerStartIndex) + mention + inputTextValue.substring(selectionEnd);
102
+ const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : defaultMentionTrigger;
103
+ // update html text with updated plain text
104
+ const [updatedHTML] = updateHTML(textValue, oldPlainText, newPlainText, tagsValue, currentTriggerStartIndex, selectionEnd, mention, triggerText);
105
+ const displayName = getDisplayNameForMentionSuggestion(suggestion, localeStrings);
106
+ // Move the caret in the text field to the end of the mention plain text
107
+ setCaretIndex(selectionEnd + displayName.length);
108
+ setCurrentTriggerStartIndex(-1);
109
+ updateMentionSuggestions([]);
110
+ setActiveSuggestionIndex(undefined);
111
+ onChange && onChange(undefined, updatedHTML);
112
+ }, [
113
+ textFieldRef,
114
+ inputTextValue,
115
+ currentTriggerStartIndex,
116
+ mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger,
117
+ onChange,
118
+ textValue,
119
+ tagsValue,
120
+ /* @conditional-compile-remove(mention) */
121
+ updateMentionSuggestions,
122
+ /* @conditional-compile-remove(mention) */
123
+ localeStrings
124
+ ]);
125
+ const onTextFieldKeyDown = useCallback((ev) => {
21
126
  // 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)
22
127
  if (ev.nativeEvent.isComposing || ev.nativeEvent.keyCode === 229 || ev.nativeEvent.which === 229) {
23
128
  return;
24
129
  }
130
+ if (ev.key === 'ArrowUp') {
131
+ ev.preventDefault();
132
+ /* @conditional-compile-remove(mention) */
133
+ if (mentionSuggestions.length > 0) {
134
+ const newActiveIndex = activeSuggestionIndex === undefined
135
+ ? mentionSuggestions.length - 1
136
+ : Math.max(activeSuggestionIndex - 1, 0);
137
+ setActiveSuggestionIndex(newActiveIndex);
138
+ }
139
+ }
140
+ else if (ev.key === 'ArrowDown') {
141
+ ev.preventDefault();
142
+ /* @conditional-compile-remove(mention) */
143
+ if (mentionSuggestions.length > 0) {
144
+ const newActiveIndex = activeSuggestionIndex === undefined
145
+ ? 0
146
+ : Math.min(activeSuggestionIndex + 1, mentionSuggestions.length - 1);
147
+ setActiveSuggestionIndex(newActiveIndex);
148
+ }
149
+ }
25
150
  if (ev.key === 'Enter' && (ev.shiftKey === false || !supportNewline)) {
26
151
  ev.preventDefault();
152
+ // If we are looking up a mention, select the focused suggestion
153
+ /* @conditional-compile-remove(mention) */
154
+ if (mentionSuggestions.length > 0 && activeSuggestionIndex !== undefined) {
155
+ const selectedMention = mentionSuggestions[activeSuggestionIndex];
156
+ if (selectedMention) {
157
+ onSuggestionSelected(selectedMention);
158
+ return;
159
+ }
160
+ }
27
161
  onEnterKeyDown && onEnterKeyDown();
28
162
  }
29
163
  onKeyDown && onKeyDown(ev);
30
- }, [onEnterKeyDown, onKeyDown, supportNewline]);
164
+ }, [
165
+ onEnterKeyDown,
166
+ onKeyDown,
167
+ supportNewline,
168
+ /* @conditional-compile-remove(mention) */
169
+ mentionSuggestions,
170
+ /* @conditional-compile-remove(mention) */
171
+ activeSuggestionIndex,
172
+ /* @conditional-compile-remove(mention) */
173
+ onSuggestionSelected
174
+ ]);
175
+ /* @conditional-compile-remove(mention) */
176
+ const debouncedQueryUpdate = useDebouncedCallback((query) => __awaiter(void 0, void 0, void 0, function* () {
177
+ var _a;
178
+ const suggestions = (_a = (yield (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.onQueryUpdated(query)))) !== null && _a !== void 0 ? _a : [];
179
+ if (suggestions.length === 0) {
180
+ setActiveSuggestionIndex(undefined);
181
+ }
182
+ else if (activeSuggestionIndex === undefined) {
183
+ setActiveSuggestionIndex(0);
184
+ }
185
+ updateMentionSuggestions(suggestions);
186
+ }), 500);
187
+ /* @conditional-compile-remove(mention) */
188
+ useEffect(() => {
189
+ return () => {
190
+ debouncedQueryUpdate.cancel();
191
+ };
192
+ }, [debouncedQueryUpdate]);
193
+ /* @conditional-compile-remove(mention) */
194
+ const handleOnChange = useCallback((event, updatedValue) => __awaiter(void 0, void 0, void 0, function* () {
195
+ var _b, _c;
196
+ const newValue = updatedValue !== null && updatedValue !== void 0 ? updatedValue : '';
197
+ const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : defaultMentionTrigger;
198
+ const newTextLength = newValue.length;
199
+ let selectionEnd = ((_c = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _c === void 0 ? void 0 : _c.selectionEnd) || -1;
200
+ selectionEnd = Math.max(0, selectionEnd);
201
+ selectionEnd = Math.min(selectionEnd, newTextLength - 1);
202
+ // If we are enabled for lookups,
203
+ if (mentionLookupOptions !== undefined) {
204
+ // Look at the range of the change for a trigger character
205
+ const triggerPriorIndex = newValue.lastIndexOf(triggerText, selectionEnd - 1);
206
+ // Update the caret position, if not doing a lookup
207
+ setCaretPosition(Caret.getRelativePosition(event.currentTarget));
208
+ if (triggerPriorIndex !== undefined) {
209
+ // trigger is found
210
+ const isSpaceBeforeTrigger = newValue.substring(triggerPriorIndex - 1, triggerPriorIndex) === ' ';
211
+ const wordAtSelection = newValue.substring(triggerPriorIndex, selectionEnd);
212
+ let tagIndex = currentTriggerStartIndex;
213
+ if (!isSpaceBeforeTrigger && triggerPriorIndex !== 0) {
214
+ //no space before the trigger <- continuation of the previous word
215
+ tagIndex = -1;
216
+ setCurrentTriggerStartIndex(tagIndex);
217
+ }
218
+ else if (wordAtSelection === triggerText) {
219
+ // start of the mention
220
+ tagIndex = selectionEnd - triggerText.length;
221
+ if (tagIndex < 0) {
222
+ tagIndex = 0;
223
+ }
224
+ setCurrentTriggerStartIndex(tagIndex);
225
+ }
226
+ if (tagIndex === -1) {
227
+ updateMentionSuggestions([]);
228
+ }
229
+ else {
230
+ // In the middle of a @mention lookup
231
+ if (tagIndex > -1) {
232
+ const query = wordAtSelection.substring(triggerText.length, wordAtSelection.length);
233
+ if (query !== undefined) {
234
+ yield debouncedQueryUpdate(query);
235
+ }
236
+ }
237
+ }
238
+ }
239
+ }
240
+ let result = '';
241
+ if (tagsValue.length === 0) {
242
+ // no tags in the string, textValue is a sting
243
+ result = newValue;
244
+ }
245
+ else {
246
+ // there are tags in the text value, textValue is html string
247
+ const { changeStart, oldChangeEnd, newChangeEnd } = findStringsDiffIndexes(inputTextValue, newValue, selectionEnd);
248
+ // get updated html string
249
+ const change = newValue.substring(changeStart, newChangeEnd);
250
+ const [updatedHTML, updatedChangeNewEndIndex] = updateHTML(textValue, inputTextValue, newValue, tagsValue, changeStart, oldChangeEnd, change, triggerText);
251
+ result = updatedHTML;
252
+ if (updatedChangeNewEndIndex !== null) {
253
+ if ((change.length === 1 && event.currentTarget.selectionStart === event.currentTarget.selectionEnd) || // simple input
254
+ (change.length === 0 && newChangeEnd === changeStart) //delete
255
+ ) {
256
+ setCaretIndex(updatedChangeNewEndIndex);
257
+ }
258
+ }
259
+ }
260
+ onChange && onChange(event, result);
261
+ }), [
262
+ onChange,
263
+ mentionLookupOptions,
264
+ tagsValue,
265
+ textValue,
266
+ inputTextValue,
267
+ currentTriggerStartIndex,
268
+ setCaretIndex,
269
+ setCaretPosition,
270
+ updateMentionSuggestions,
271
+ debouncedQueryUpdate,
272
+ textFieldRef
273
+ ]);
274
+ /* @conditional-compile-remove(mention) */
275
+ const updateSelectionIndexesWithMentionIfNeeded = (event) => {
276
+ var _a;
277
+ let updatedStartIndex = event.currentTarget.selectionStart;
278
+ let updatedEndIndex = event.currentTarget.selectionEnd;
279
+ if (event.currentTarget.selectionStart === event.currentTarget.selectionEnd &&
280
+ event.currentTarget.selectionStart !== null &&
281
+ event.currentTarget.selectionStart !== -1) {
282
+ const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
283
+ if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
284
+ if (selectionStartValue === null) {
285
+ updatedStartIndex = mentionTag.plainTextBeginIndex;
286
+ updatedEndIndex = (_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex;
287
+ }
288
+ else {
289
+ const newSelectionIndex = findNewSelectionIndexForMention(mentionTag, inputTextValue, event.currentTarget.selectionStart, selectionStartValue);
290
+ updatedStartIndex = newSelectionIndex;
291
+ updatedEndIndex = newSelectionIndex;
292
+ }
293
+ }
294
+ }
295
+ else if (event.currentTarget.selectionStart !== event.currentTarget.selectionEnd) {
296
+ // Both e.currentTarget.selectionStart !== selectionStartValue and e.currentTarget.selectionEnd !== selectionEndValue can be true when a user selects a text by double click
297
+ if (event.currentTarget.selectionStart !== null && event.currentTarget.selectionStart !== selectionStartValue) {
298
+ // the selection start is changed
299
+ const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
300
+ if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
301
+ //TODO: here it takes -1 when it shouldn't, update selectionstart and end with mouse move and or touch move
302
+ updatedStartIndex = findNewSelectionIndexForMention(mentionTag, inputTextValue, event.currentTarget.selectionStart, selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : -1);
303
+ }
304
+ }
305
+ if (event.currentTarget.selectionEnd !== null && event.currentTarget.selectionEnd !== selectionEndValue) {
306
+ // the selection end is changed
307
+ const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionEnd);
308
+ if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
309
+ //TODO: here it takes -1 when it shouldn't, update selectionstart and end with mouse move and or touch move
310
+ updatedEndIndex = findNewSelectionIndexForMention(mentionTag, inputTextValue, event.currentTarget.selectionEnd, selectionEndValue !== null && selectionEndValue !== void 0 ? selectionEndValue : -1);
311
+ }
312
+ }
313
+ }
314
+ // e.currentTarget.selectionDirection should be set to handle shift + arrow keys
315
+ if (event.currentTarget.selectionDirection === null) {
316
+ event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex);
317
+ }
318
+ else {
319
+ event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex, event.currentTarget.selectionDirection);
320
+ }
321
+ setSelectionStartValue(updatedStartIndex);
322
+ setSelectionEndValue(updatedEndIndex);
323
+ };
324
+ const getInputFieldTextValue = () => {
325
+ /* @conditional-compile-remove(mention) */
326
+ return inputTextValue;
327
+ return textValue;
328
+ };
31
329
  return (React.createElement(Stack, { className: mergedRootStyle },
32
330
  React.createElement("div", { className: mergedTextContainerStyle },
33
- React.createElement(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: textValue, onChange: onChange, autoComplete: "off", onKeyDown: onTexFieldKeyDown, styles: mergedTextFieldStyle, disabled: disabled, errorMessage: errorMessage }),
331
+ /* @conditional-compile-remove(mention) */ mentionSuggestions.length > 0 && (React.createElement(_MentionPopover, { suggestions: mentionSuggestions, activeSuggestionIndex: activeSuggestionIndex, target: inputBoxRef, targetPositionOffset: caretPosition, onRenderSuggestionItem: mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.onRenderSuggestionItem, onSuggestionSelected: onSuggestionSelected, onDismiss: () => {
332
+ updateMentionSuggestions([]);
333
+ } })),
334
+ React.createElement(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) => {
335
+ /* @conditional-compile-remove(mention) */
336
+ setInputTextValue(newValue !== null && newValue !== void 0 ? newValue : '');
337
+ /* @conditional-compile-remove(mention) */
338
+ handleOnChange(e, newValue);
339
+ /* @conditional-compile-remove(mention) */
340
+ return;
341
+ onChange(e, newValue);
342
+ },
343
+ /* @conditional-compile-remove(mention) */
344
+ onSelect: (e) => {
345
+ var _a, _b, _c;
346
+ if (caretIndex !== undefined) {
347
+ e.currentTarget.setSelectionRange(caretIndex, caretIndex);
348
+ setCaretIndex(undefined);
349
+ return;
350
+ }
351
+ //TODO: need to check to navigate before/after space correctly in tag + when selecting by mouse
352
+ /* @conditional-compile-remove(mention) */
353
+ if (shouldHandleOnMouseDownDuringSelect &&
354
+ e.currentTarget.selectionStart !== null &&
355
+ e.currentTarget.selectionStart === e.currentTarget.selectionEnd) {
356
+ // handle mention click
357
+ const mentionTag = findMentionTagForSelection(tagsValue, e.currentTarget.selectionStart);
358
+ if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
359
+ if (e.currentTarget.selectionDirection === null) {
360
+ e.currentTarget.setSelectionRange(mentionTag.plainTextBeginIndex, (_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex);
361
+ }
362
+ else {
363
+ e.currentTarget.setSelectionRange(mentionTag.plainTextBeginIndex, (_b = mentionTag.plainTextEndIndex) !== null && _b !== void 0 ? _b : mentionTag.plainTextBeginIndex, e.currentTarget.selectionDirection);
364
+ }
365
+ setSelectionStartValue(mentionTag.plainTextBeginIndex);
366
+ setSelectionEndValue((_c = mentionTag.plainTextEndIndex) !== null && _c !== void 0 ? _c : mentionTag.plainTextBeginIndex);
367
+ }
368
+ else {
369
+ setSelectionStartValue(e.currentTarget.selectionStart);
370
+ setSelectionEndValue(e.currentTarget.selectionEnd);
371
+ }
372
+ }
373
+ else {
374
+ updateSelectionIndexesWithMentionIfNeeded(e);
375
+ }
376
+ /* @conditional-compile-remove(mention) */
377
+ setShouldHandleOnMouseDownDuringSelect(false);
378
+ }, onMouseDown: () => {
379
+ // as events order is onMouseDown -> onSelect -> onClick
380
+ // onClick and onMouseDown can't handle clicking on mention event because
381
+ // onClick has wrong range as it's called after onSelect
382
+ // onMouseDown doesn't have correct selectionRange yet
383
+ // so we need to handle onMouseDown to prevent onSelect default behavior
384
+ /* @conditional-compile-remove(mention) */
385
+ setShouldHandleOnMouseDownDuringSelect(true);
386
+ }, onTouchStart: () => {
387
+ // see onMouseDown for more details
388
+ /* @conditional-compile-remove(mention) */
389
+ setShouldHandleOnMouseDownDuringSelect(true);
390
+ }, autoComplete: "off", onKeyDown: onTextFieldKeyDown, styles: mergedTextFieldStyle, disabled: disabled, errorMessage: errorMessage, elementRef: inputBoxRef }),
34
391
  React.createElement(Stack, { horizontal: true, className: mergeStyles(props.inlineChildren ? inlineButtonsContainerStyle : newLineButtonsContainerStyle) }, children))));
35
392
  };
36
393
  /**
@@ -55,4 +412,680 @@ export const InputBoxButton = (props) => {
55
412
  setIsHover(false);
56
413
  }, onRenderIcon: () => onRenderIcon(isHover) })));
57
414
  };
415
+ /* @conditional-compile-remove(mention) */
416
+ /**
417
+ * Find mention tag if selection is inside of it
418
+ *
419
+ * @private
420
+ */
421
+ const findMentionTagForSelection = (tags, selection) => {
422
+ let mentionTag = undefined;
423
+ for (let i = 0; i < tags.length; i++) {
424
+ const tag = tags[i];
425
+ let plainTextEndIndex = 0;
426
+ if (tag.plainTextEndIndex !== undefined && tag.closeTagIdx !== undefined) {
427
+ // close tag exists
428
+ plainTextEndIndex = tag.plainTextEndIndex;
429
+ }
430
+ else if (tag.plainTextBeginIndex !== undefined) {
431
+ //no close tag
432
+ plainTextEndIndex = tag.plainTextBeginIndex;
433
+ }
434
+ if (tag.subTags !== undefined && tag.subTags.length !== 0) {
435
+ const selectedTag = findMentionTagForSelection(tag.subTags, selection);
436
+ if (selectedTag !== undefined) {
437
+ mentionTag = selectedTag;
438
+ break;
439
+ }
440
+ }
441
+ else if (tag.tagType === 'msft-mention' &&
442
+ tag.plainTextBeginIndex !== undefined &&
443
+ tag.plainTextBeginIndex < selection &&
444
+ selection < plainTextEndIndex) {
445
+ mentionTag = tag;
446
+ break;
447
+ }
448
+ }
449
+ return mentionTag;
450
+ };
451
+ /* @conditional-compile-remove(mention) */
452
+ /**
453
+ * Go through tags and find a new the selection index if it is inside of a mention tag
454
+ *
455
+ * @private
456
+ */
457
+ const findNewSelectionIndexForMention = (tag, textValue, selection, previousSelection) => {
458
+ var _a;
459
+ if (tag.plainTextBeginIndex === undefined ||
460
+ tag.tagType !== 'msft-mention' ||
461
+ selection === previousSelection ||
462
+ tag.plainTextEndIndex === undefined) {
463
+ return selection;
464
+ }
465
+ let spaceIndex = 0;
466
+ if (selection <= previousSelection) {
467
+ // the cursor is moved to the left
468
+ spaceIndex = textValue.lastIndexOf(' ', selection !== null && selection !== void 0 ? selection : 0);
469
+ if (spaceIndex === -1) {
470
+ // no space before the selection
471
+ spaceIndex = tag.plainTextBeginIndex;
472
+ }
473
+ }
474
+ else {
475
+ // the cursor is moved to the right
476
+ spaceIndex = textValue.indexOf(' ', selection !== null && selection !== void 0 ? selection : 0);
477
+ if (spaceIndex === -1) {
478
+ // no space after the selection
479
+ spaceIndex = (_a = tag.plainTextEndIndex) !== null && _a !== void 0 ? _a : tag.plainTextBeginIndex;
480
+ }
481
+ }
482
+ if (spaceIndex < tag.plainTextBeginIndex) {
483
+ spaceIndex = tag.plainTextBeginIndex;
484
+ }
485
+ else if (spaceIndex > tag.plainTextEndIndex) {
486
+ spaceIndex = tag.plainTextEndIndex;
487
+ }
488
+ return spaceIndex;
489
+ };
490
+ /* @conditional-compile-remove(mention) */
491
+ /**
492
+ * Handle mention tag edit and by word deleting
493
+ *
494
+ * @private
495
+ */
496
+ const handleMentionTagUpdate = (htmlText, oldPlainText, lastProcessedHTMLIndex, processedChange, tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength) => {
497
+ if (tag.tagType !== 'msft-mention' || tag.plainTextBeginIndex === undefined) {
498
+ return ['', processedChange, lastProcessedHTMLIndex, null];
499
+ }
500
+ let result = '';
501
+ let plainTextSelectionEndIndex = null;
502
+ let rangeStart;
503
+ let rangeEnd;
504
+ // check if space symbol is handled in case if string looks like '<1 2 3>'
505
+ let isSpaceLengthHandled = false;
506
+ rangeStart = oldPlainText.lastIndexOf(' ', startIndex);
507
+ if (rangeStart !== -1 && rangeStart !== undefined && rangeStart > tag.plainTextBeginIndex) {
508
+ isSpaceLengthHandled = true;
509
+ }
510
+ rangeEnd = oldPlainText.indexOf(' ', oldPlainTextEndIndex);
511
+ if (rangeEnd === -1 || rangeEnd === undefined) {
512
+ // check if space symbol is not found
513
+ rangeEnd = plainTextEndIndex;
514
+ }
515
+ else if (!isSpaceLengthHandled) {
516
+ // +1 to include the space symbol
517
+ rangeEnd += 1;
518
+ }
519
+ isSpaceLengthHandled = true;
520
+ if (rangeStart === -1 || rangeStart === undefined || rangeStart < tag.plainTextBeginIndex) {
521
+ rangeStart = tag.plainTextBeginIndex;
522
+ }
523
+ if (rangeEnd > plainTextEndIndex) {
524
+ rangeEnd = plainTextEndIndex;
525
+ }
526
+ if (rangeStart === tag.plainTextBeginIndex && rangeEnd === plainTextEndIndex) {
527
+ // the whole tag should be removed
528
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx) + processedChange;
529
+ plainTextSelectionEndIndex = tag.plainTextBeginIndex + processedChange.length;
530
+ processedChange = '';
531
+ lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
532
+ }
533
+ else {
534
+ // only part of the tag should be removed
535
+ let startChangeDiff = 0;
536
+ let endChangeDiff = 0;
537
+ // need to check only rangeStart > tag.plainTextBeginIndex as when rangeStart === tag.plainTextBeginIndex startChangeDiff = 0 and mentionTagLength shouldn't be subtracted
538
+ if (rangeStart > tag.plainTextBeginIndex) {
539
+ startChangeDiff = rangeStart - tag.plainTextBeginIndex - mentionTagLength;
540
+ }
541
+ endChangeDiff = rangeEnd - tag.plainTextBeginIndex - mentionTagLength;
542
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length + startChangeDiff);
543
+ // plainTextSelectionEndIndex = rangeStart + processedChange.length;
544
+ lastProcessedHTMLIndex = tag.openTagIdx + tag.openTagBody.length + endChangeDiff;
545
+ // processed change should not be changed as it should be added after the tag
546
+ }
547
+ return [result, processedChange, lastProcessedHTMLIndex, plainTextSelectionEndIndex];
548
+ };
549
+ /* @conditional-compile-remove(mention) */
550
+ /**
551
+ * Go through the text and update it with the changed text
552
+ *
553
+ * @private
554
+ */
555
+ const updateHTML = (htmlText, oldPlainText, newPlainText, tags, startIndex, oldPlainTextEndIndex, change, mentionTrigger) => {
556
+ let result = '';
557
+ if (tags.length === 0) {
558
+ // no tags added yet
559
+ return [newPlainText, null];
560
+ }
561
+ if (startIndex === 0 && oldPlainTextEndIndex === oldPlainText.length) {
562
+ // the whole text is changed
563
+ return [newPlainText, null];
564
+ }
565
+ let lastProcessedHTMLIndex = 0;
566
+ // the value can be updated with empty string when the change covers more than 1 place (tag + before or after the tag)
567
+ // in this case change won't be added as part of the tag
568
+ // e.g.: change is before and partially in tag => change will be added before the tag and outdated text in the tag will be removed
569
+ // 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
570
+ // e.g.: change is on the beginning of the tag => change will be added before the tag
571
+ // 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
572
+ let processedChange = change;
573
+ // end tag plain text index of the last processed tag
574
+ let lastProcessedPlainTextTagEndIndex = 0;
575
+ // as some tags/text can be removed fully, selectionEnd should be updated correctly
576
+ let changeNewEndIndex = null;
577
+ for (let i = 0; i < tags.length; i++) {
578
+ const tag = tags[i];
579
+ if (tag.plainTextBeginIndex === undefined) {
580
+ continue;
581
+ }
582
+ // all plain text indexes includes trigger length for the mention that shouldn't be included in
583
+ // htmlText.substring because html strings don't include the trigger
584
+ // mentionTagLength will be set only for 'msft-mention', otherwise should be 0
585
+ let mentionTagLength = 0;
586
+ let isMentionTag = false;
587
+ if (tag.tagType === 'msft-mention') {
588
+ mentionTagLength = mentionTrigger.length;
589
+ isMentionTag = true;
590
+ }
591
+ //change start is before the open tag
592
+ if (startIndex <= tag.plainTextBeginIndex) {
593
+ // Math.max(lastProcessedPlainTextTagEndIndex, startIndex) is used as startIndex may not be in [[previous tag].plainTextEndIndex - tag.plainTextBeginIndex] range
594
+ const startChangeDiff = tag.plainTextBeginIndex - Math.max(lastProcessedPlainTextTagEndIndex, startIndex);
595
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx - startChangeDiff) + processedChange;
596
+ if (oldPlainTextEndIndex <= tag.plainTextBeginIndex) {
597
+ // the whole change is before tag start
598
+ // oldPlainTextEndIndex already includes mentionTag length
599
+ const endChangeDiff = tag.plainTextBeginIndex - oldPlainTextEndIndex;
600
+ lastProcessedHTMLIndex = tag.openTagIdx - endChangeDiff;
601
+ processedChange = '';
602
+ // the change is handled; exit
603
+ break;
604
+ }
605
+ else {
606
+ // change continues in the tag
607
+ lastProcessedHTMLIndex = tag.openTagIdx;
608
+ processedChange = '';
609
+ // proceed to the next check
610
+ }
611
+ }
612
+ let plainTextEndIndex = 0;
613
+ let closeTagIdx = 0;
614
+ let closeTagLength = 0;
615
+ if (tag.plainTextEndIndex !== undefined && tag.closeTagIdx !== undefined) {
616
+ // close tag exists
617
+ plainTextEndIndex = tag.plainTextEndIndex;
618
+ closeTagIdx = tag.closeTagIdx;
619
+ // tag.tagType.length + </>
620
+ closeTagLength = tag.tagType.length + 3;
621
+ }
622
+ else {
623
+ // no close tag
624
+ plainTextEndIndex = tag.plainTextBeginIndex;
625
+ closeTagIdx = tag.openTagIdx + tag.openTagBody.length;
626
+ closeTagLength = 0;
627
+ }
628
+ if (startIndex < plainTextEndIndex) {
629
+ // change started before the end tag
630
+ if (startIndex <= tag.plainTextBeginIndex && oldPlainTextEndIndex === plainTextEndIndex) {
631
+ // the change is a tag or starts before the tag
632
+ // tag should be removed, no matter if there are subtags
633
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx) + processedChange;
634
+ processedChange = '';
635
+ lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
636
+ // the change is handled; exit
637
+ break;
638
+ }
639
+ else if (startIndex >= tag.plainTextBeginIndex && oldPlainTextEndIndex < plainTextEndIndex) {
640
+ // edge case: the change is between tag
641
+ if (isMentionTag) {
642
+ if (change !== '') {
643
+ // mention tag should be deleted when user tries to edit it
644
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx) + processedChange;
645
+ changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
646
+ processedChange = '';
647
+ lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
648
+ }
649
+ else {
650
+ const [resultValue, updatedChange, htmlIndex, plainTextSelectionEndIndex] = handleMentionTagUpdate(htmlText, oldPlainText, lastProcessedHTMLIndex, processedChange, tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength);
651
+ result += resultValue;
652
+ changeNewEndIndex = plainTextSelectionEndIndex;
653
+ processedChange = updatedChange;
654
+ lastProcessedHTMLIndex = htmlIndex;
655
+ }
656
+ // the change is handled; exit
657
+ break;
658
+ }
659
+ else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content) {
660
+ // with subtags
661
+ // before the tag content
662
+ const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length);
663
+ lastProcessedHTMLIndex = closeTagIdx;
664
+ const [content, updatedChangeNewEndIndex] = updateHTML(tag.content, oldPlainText, newPlainText, tag.subTags, startIndex - mentionTagLength, oldPlainTextEndIndex - mentionTagLength, processedChange, mentionTrigger);
665
+ result += stringBefore + content;
666
+ changeNewEndIndex = updatedChangeNewEndIndex;
667
+ break;
668
+ }
669
+ else {
670
+ // no subtags
671
+ const startChangeDiff = startIndex - tag.plainTextBeginIndex - mentionTagLength;
672
+ const endChangeDiff = oldPlainTextEndIndex - tag.plainTextBeginIndex - mentionTagLength;
673
+ result +=
674
+ htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length + startChangeDiff) +
675
+ processedChange;
676
+ processedChange = '';
677
+ lastProcessedHTMLIndex = tag.openTagIdx + tag.openTagBody.length + endChangeDiff;
678
+ // the change is handled; exit
679
+ break;
680
+ }
681
+ }
682
+ else if (startIndex > tag.plainTextBeginIndex && oldPlainTextEndIndex > plainTextEndIndex) {
683
+ //the change started in the tag but finishes somewhere further
684
+ const startChangeDiff = startIndex - tag.plainTextBeginIndex - mentionTagLength;
685
+ if (isMentionTag) {
686
+ 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
687
+ tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength);
688
+ result += resultValue;
689
+ lastProcessedHTMLIndex = htmlIndex;
690
+ processedChange = updatedChange;
691
+ // no need to handle plainTextSelectionEndIndex as the change will be added later
692
+ // proceed with the next calculations
693
+ }
694
+ else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
695
+ // with subtags
696
+ // before the tag content
697
+ const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length);
698
+ lastProcessedHTMLIndex = closeTagIdx;
699
+ 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
700
+ mentionTrigger);
701
+ result += stringBefore + content;
702
+ // proceed with the next calculations
703
+ }
704
+ else {
705
+ // no subtags
706
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length + startChangeDiff);
707
+ lastProcessedHTMLIndex = closeTagIdx;
708
+ // proceed with the next calculations
709
+ }
710
+ }
711
+ else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex > plainTextEndIndex) {
712
+ // the change starts before the tag and finishes after it
713
+ // tag should be removed, no matter if there are subtags
714
+ // no need to save anything between lastProcessedHTMLIndex and closeTagIdx + closeTagLength
715
+ lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
716
+ // proceed with the next calculations
717
+ }
718
+ else if (startIndex === tag.plainTextBeginIndex && oldPlainTextEndIndex > plainTextEndIndex) {
719
+ // the change starts in the tag and finishes after it
720
+ // tag should be removed, no matter if there are subtags
721
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx);
722
+ // processedChange shouldn't be updated as it will be added after the tag
723
+ lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
724
+ // proceed with the next calculations
725
+ }
726
+ else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex < plainTextEndIndex) {
727
+ // the change starts before the tag and ends in a tag
728
+ if (isMentionTag) {
729
+ const [resultValue, , htmlIndex] = handleMentionTagUpdate(htmlText, oldPlainText, lastProcessedHTMLIndex, '', // the part of mention should be just deleted without processedChange update
730
+ tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength);
731
+ changeNewEndIndex = tag.plainTextBeginIndex;
732
+ result += resultValue;
733
+ lastProcessedHTMLIndex = htmlIndex;
734
+ }
735
+ else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
736
+ // with subtags
737
+ // before the tag content
738
+ const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length);
739
+ lastProcessedHTMLIndex = closeTagIdx;
740
+ 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
741
+ mentionTrigger);
742
+ result += stringBefore + content;
743
+ }
744
+ else {
745
+ // no subtags
746
+ result +=
747
+ htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length) + processedChange;
748
+ processedChange = '';
749
+ // oldPlainTextEndIndex already includes mentionTag length
750
+ const endChangeDiff = plainTextEndIndex - oldPlainTextEndIndex;
751
+ // as change may be before the end of the tag, we need to add the rest of the tag
752
+ lastProcessedHTMLIndex = closeTagIdx - endChangeDiff;
753
+ }
754
+ // the change is handled; exit
755
+ break;
756
+ }
757
+ else if (startIndex > tag.plainTextBeginIndex && oldPlainTextEndIndex === plainTextEndIndex) {
758
+ // the change starts in the tag and ends at the end of a tag
759
+ if (isMentionTag) {
760
+ if (change !== '' && startIndex === plainTextEndIndex) {
761
+ // non empty change at the end of the mention tag to be added after the mention tag
762
+ result += htmlText.substring(lastProcessedHTMLIndex, closeTagIdx + closeTagLength) + processedChange;
763
+ changeNewEndIndex = plainTextEndIndex + processedChange.length;
764
+ processedChange = '';
765
+ lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
766
+ }
767
+ else if (change !== '') {
768
+ // mention tag should be deleted when user tries to edit it
769
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx) + processedChange;
770
+ changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
771
+ processedChange = '';
772
+ lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
773
+ }
774
+ else {
775
+ const [resultValue, updatedChange, htmlIndex, plainTextSelectionEndIndex] = handleMentionTagUpdate(htmlText, oldPlainText, lastProcessedHTMLIndex, processedChange, tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength);
776
+ result += resultValue;
777
+ processedChange = updatedChange;
778
+ lastProcessedHTMLIndex = htmlIndex;
779
+ changeNewEndIndex = plainTextSelectionEndIndex;
780
+ }
781
+ // the change is handled; exit
782
+ break;
783
+ }
784
+ else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
785
+ // with subtags
786
+ // before the tag content
787
+ const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length);
788
+ lastProcessedHTMLIndex = closeTagIdx;
789
+ const [content, updatedChangeNewEndIndex] = updateHTML(tag.content, oldPlainText, newPlainText, tag.subTags, startIndex - mentionTagLength, oldPlainTextEndIndex - mentionTagLength, processedChange, mentionTrigger);
790
+ result += stringBefore + content;
791
+ changeNewEndIndex = updatedChangeNewEndIndex;
792
+ break;
793
+ }
794
+ else {
795
+ // no subtags
796
+ const startChangeDiff = startIndex - tag.plainTextBeginIndex - mentionTagLength;
797
+ result +=
798
+ htmlText.substring(lastProcessedHTMLIndex, tag.openTagIdx + tag.openTagBody.length + startChangeDiff) +
799
+ processedChange;
800
+ processedChange = '';
801
+ lastProcessedHTMLIndex = closeTagIdx;
802
+ // the change is handled; exit
803
+ break;
804
+ }
805
+ }
806
+ lastProcessedPlainTextTagEndIndex = plainTextEndIndex;
807
+ }
808
+ if (i === tags.length - 1 && oldPlainTextEndIndex >= plainTextEndIndex) {
809
+ // the last tag should handle the end of the change if needed
810
+ // oldPlainTextEndIndex already includes mentionTag length
811
+ const endChangeDiff = oldPlainTextEndIndex - plainTextEndIndex;
812
+ if (startIndex >= plainTextEndIndex) {
813
+ const startChangeDiff = startIndex - plainTextEndIndex;
814
+ result +=
815
+ htmlText.substring(lastProcessedHTMLIndex, closeTagIdx + closeTagLength + startChangeDiff) + processedChange;
816
+ }
817
+ else {
818
+ result += htmlText.substring(lastProcessedHTMLIndex, closeTagIdx + closeTagLength) + processedChange;
819
+ }
820
+ processedChange = '';
821
+ lastProcessedHTMLIndex = closeTagIdx + closeTagLength + endChangeDiff;
822
+ // the change is handled; exit
823
+ // break is not required here as this is the last element but added for consistency
824
+ break;
825
+ }
826
+ }
827
+ if (lastProcessedHTMLIndex < htmlText.length) {
828
+ result += htmlText.substring(lastProcessedHTMLIndex);
829
+ }
830
+ return [result, changeNewEndIndex];
831
+ };
832
+ /* @conditional-compile-remove(mention) */
833
+ /**
834
+ * Given the oldText and newText, find the start index, old end index and new end index for the changes
835
+ *
836
+ * @param oldText - the old text
837
+ * @param newText - the new text
838
+ * @param selectionEnd - the end of the selection
839
+ * @returns change start index, old end index and new end index. The old and new end indexes are exclusive.
840
+ * @private
841
+ */
842
+ const findStringsDiffIndexes = (oldText, newText, selectionEnd // should be a valid position in the input field
843
+ ) => {
844
+ const newTextLength = newText.length;
845
+ const oldTextLength = oldText.length;
846
+ let changeStart = 0;
847
+ let newChangeEnd = newTextLength;
848
+ let oldChangeEnd = oldTextLength;
849
+ const length = Math.min(newTextLength, oldTextLength, selectionEnd);
850
+ for (let i = 0; i < length; i++) {
851
+ if (newText[i] !== oldText[i]) {
852
+ // the symbol with changeStart index is updated
853
+ changeStart = i;
854
+ break;
855
+ }
856
+ else if (i === length - 1 && newText[i] === oldText[i]) {
857
+ // the symbol is added at the end of inputTextValue
858
+ changeStart = length;
859
+ break;
860
+ }
861
+ }
862
+ if (oldTextLength < newTextLength) {
863
+ //insert or replacement
864
+ if (oldTextLength === changeStart) {
865
+ // when change was at the end of string
866
+ // Change is found
867
+ newChangeEnd = newTextLength;
868
+ oldChangeEnd = oldTextLength;
869
+ }
870
+ else {
871
+ for (let i = 1; i < newTextLength && oldTextLength - i >= changeStart; i++) {
872
+ newChangeEnd = newTextLength - i - 1;
873
+ oldChangeEnd = oldTextLength - i - 1;
874
+ if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
875
+ // Change is found
876
+ break;
877
+ }
878
+ }
879
+ // make indexes exclusive
880
+ newChangeEnd += 1;
881
+ oldChangeEnd += 1;
882
+ }
883
+ }
884
+ else if (oldTextLength > newTextLength) {
885
+ //deletion or replacement
886
+ if (newTextLength === changeStart) {
887
+ // when change was at the end of string
888
+ // Change is found
889
+ newChangeEnd = newTextLength;
890
+ oldChangeEnd = oldTextLength;
891
+ }
892
+ else {
893
+ for (let i = 1; i < oldTextLength && newTextLength - i >= changeStart; i++) {
894
+ newChangeEnd = newTextLength - i - 1;
895
+ oldChangeEnd = oldTextLength - i - 1;
896
+ if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
897
+ // Change is found
898
+ break;
899
+ }
900
+ }
901
+ // make indexes exclusive
902
+ newChangeEnd += 1;
903
+ oldChangeEnd += 1;
904
+ }
905
+ }
906
+ else {
907
+ //replacement
908
+ for (let i = 1; i < oldTextLength && oldTextLength - i >= changeStart; i++) {
909
+ newChangeEnd = newTextLength - i - 1;
910
+ oldChangeEnd = oldTextLength - i - 1;
911
+ if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
912
+ // Change is found
913
+ break;
914
+ }
915
+ }
916
+ // make indexes exclusive if they aren't equal to the length of the string
917
+ if (newChangeEnd !== newText.length) {
918
+ newChangeEnd += 1;
919
+ }
920
+ if (oldChangeEnd !== oldText.length) {
921
+ oldChangeEnd += 1;
922
+ }
923
+ }
924
+ return { changeStart, oldChangeEnd, newChangeEnd };
925
+ };
926
+ /* @conditional-compile-remove(mention) */
927
+ const htmlStringForMentionSuggestion = (suggestion, localeStrings) => {
928
+ const idHTML = ' id ="' + suggestion.id + '"';
929
+ const displayTextHTML = ' displayText ="' + suggestion.displayText + '"';
930
+ const displayText = getDisplayNameForMentionSuggestion(suggestion, localeStrings);
931
+ return '<msft-mention' + idHTML + displayTextHTML + '>' + displayText + '</msft-mention>';
932
+ };
933
+ /* @conditional-compile-remove(mention) */
934
+ const getDisplayNameForMentionSuggestion = (suggestion, localeStrings) => {
935
+ const displayNamePlaceholder = localeStrings.participantItem.displayNamePlaceholder;
936
+ return suggestion.displayText !== '' ? suggestion.displayText : displayNamePlaceholder !== null && displayNamePlaceholder !== void 0 ? displayNamePlaceholder : '';
937
+ };
938
+ /* @conditional-compile-remove(mention) */
939
+ /**
940
+ * Parse the text and return the tags and the plain text in one go
941
+ * @param text - The text to parse for HTML tags
942
+ * @param trigger The trigger to show for the msft-mention tag in plain text
943
+ *
944
+ * @returns An array of tags and the plain text representation
945
+ */
946
+ const textToTagParser = (text, trigger) => {
947
+ var _a, _b;
948
+ const tags = []; // Tags passed back to the caller
949
+ const tagParseStack = []; // Local stack to use while parsing
950
+ let plainTextRepresentation = '';
951
+ let parseIndex = 0;
952
+ while (parseIndex < text.length) {
953
+ const foundHtmlTag = findNextHtmlTag(text, parseIndex);
954
+ if (!foundHtmlTag) {
955
+ if (parseIndex !== 0) {
956
+ // Add the remaining text to the plain text representation
957
+ plainTextRepresentation += text.substring(parseIndex);
958
+ }
959
+ else {
960
+ plainTextRepresentation = text;
961
+ }
962
+ break;
963
+ }
964
+ if (foundHtmlTag.type === 'open' || foundHtmlTag.type === 'self-closing') {
965
+ const nextTag = parseOpenTag(foundHtmlTag.content, foundHtmlTag.startIdx);
966
+ // Add the plain text between the last tag and this one found
967
+ plainTextRepresentation += text.substring(parseIndex, foundHtmlTag.startIdx);
968
+ nextTag.plainTextBeginIndex = plainTextRepresentation.length;
969
+ if (foundHtmlTag.type === 'open') {
970
+ tagParseStack.push(nextTag);
971
+ }
972
+ else {
973
+ nextTag.content = '';
974
+ nextTag.plainTextBeginIndex = plainTextRepresentation.length;
975
+ nextTag.plainTextEndIndex = plainTextRepresentation.length;
976
+ addTag(nextTag, tagParseStack, tags);
977
+ }
978
+ }
979
+ if (foundHtmlTag.type === 'close') {
980
+ const currentOpenTag = tagParseStack.pop();
981
+ const closeTagType = foundHtmlTag.content.substring(2, foundHtmlTag.content.length - 1).toLowerCase();
982
+ if (currentOpenTag && currentOpenTag.tagType === closeTagType) {
983
+ // Tag startIdx is absolute to the text. This is updated later to be relative to the parent tag
984
+ currentOpenTag.content = text.substring(currentOpenTag.openTagIdx + currentOpenTag.openTagBody.length, foundHtmlTag.startIdx);
985
+ // Insert the plain text pieces for the sub tags
986
+ if (currentOpenTag.tagType === 'msft-mention') {
987
+ plainTextRepresentation =
988
+ plainTextRepresentation.slice(0, currentOpenTag.plainTextBeginIndex) +
989
+ trigger +
990
+ plainTextRepresentation.slice(currentOpenTag.plainTextBeginIndex);
991
+ }
992
+ if (!currentOpenTag.subTags) {
993
+ plainTextRepresentation += currentOpenTag.content;
994
+ }
995
+ else if (currentOpenTag.subTags.length > 0) {
996
+ // Add text after the last tag
997
+ const lastSubTag = currentOpenTag.subTags[currentOpenTag.subTags.length - 1];
998
+ const startOfRemainingText = ((_a = lastSubTag.closeTagIdx) !== null && _a !== void 0 ? _a : lastSubTag.openTagIdx) + lastSubTag.tagType.length + 3;
999
+ const trailingText = currentOpenTag.content.substring(startOfRemainingText);
1000
+ plainTextRepresentation += trailingText;
1001
+ }
1002
+ currentOpenTag.plainTextEndIndex = plainTextRepresentation.length;
1003
+ addTag(currentOpenTag, tagParseStack, tags);
1004
+ }
1005
+ else {
1006
+ console.error('Unexpected close tag found. Got "' +
1007
+ closeTagType +
1008
+ '" but expected "' +
1009
+ ((_b = tagParseStack[tagParseStack.length - 1]) === null || _b === void 0 ? void 0 : _b.tagType) +
1010
+ '"');
1011
+ }
1012
+ }
1013
+ // Update parsing index; move past the end of the close tag
1014
+ parseIndex = foundHtmlTag.startIdx + foundHtmlTag.content.length;
1015
+ } // While parseIndex < text.length loop
1016
+ return [tags, plainTextRepresentation];
1017
+ };
1018
+ /* @conditional-compile-remove(mention) */
1019
+ const parseOpenTag = (tag, startIdx) => {
1020
+ const tagType = tag
1021
+ .substring(1, tag.length - 1)
1022
+ .split(' ')[0]
1023
+ .toLowerCase()
1024
+ .replace('/', '');
1025
+ return {
1026
+ tagType,
1027
+ openTagIdx: startIdx,
1028
+ openTagBody: tag
1029
+ };
1030
+ };
1031
+ /* @conditional-compile-remove(mention) */
1032
+ const findNextHtmlTag = (text, startIndex) => {
1033
+ const tagStartIndex = text.indexOf('<', startIndex);
1034
+ if (tagStartIndex === -1) {
1035
+ // No more tags
1036
+ return undefined;
1037
+ }
1038
+ const tagEndIndex = text.indexOf('>', tagStartIndex);
1039
+ if (tagEndIndex === -1) {
1040
+ // No close tag
1041
+ return undefined;
1042
+ }
1043
+ const tag = text.substring(tagStartIndex, tagEndIndex + 1);
1044
+ let type = 'open';
1045
+ if (tag[1] === '/') {
1046
+ type = 'close';
1047
+ }
1048
+ else if (tag[tag.length - 2] === '/') {
1049
+ type = 'self-closing';
1050
+ }
1051
+ return {
1052
+ content: tag,
1053
+ startIdx: tagStartIndex,
1054
+ type
1055
+ };
1056
+ };
1057
+ /* @conditional-compile-remove(mention) */
1058
+ const addTag = (tag, parseStack, tags) => {
1059
+ var _a;
1060
+ // Add as sub-tag to the parent stack tag, if there is one
1061
+ const parentTag = parseStack[parseStack.length - 1];
1062
+ if (parentTag) {
1063
+ // Adjust the open tag index to be relative to the parent tag
1064
+ const parentContentStartIdx = parentTag.openTagIdx + parentTag.openTagBody.length;
1065
+ const relativeIdx = tag.openTagIdx - parentContentStartIdx;
1066
+ tag.openTagIdx = relativeIdx;
1067
+ }
1068
+ if (!tag.closeTagIdx) {
1069
+ // If the tag is self-closing, the close tag is the same as the open tag
1070
+ if (tag.openTagBody[tag.openTagBody.length - 2] === '/') {
1071
+ tag.closeTagIdx = tag.openTagIdx;
1072
+ }
1073
+ else {
1074
+ // Otherwise, the close tag index is the open tag index + the open tag body + the content length
1075
+ tag.closeTagIdx = tag.openTagIdx + tag.openTagBody.length + ((_a = tag.content) !== null && _a !== void 0 ? _a : []).length;
1076
+ }
1077
+ }
1078
+ // Put the tag where it belongs
1079
+ if (!parentTag) {
1080
+ tags.push(tag);
1081
+ }
1082
+ else {
1083
+ if (!parentTag.subTags) {
1084
+ parentTag.subTags = [tag];
1085
+ }
1086
+ else {
1087
+ parentTag.subTags.push(tag);
1088
+ }
1089
+ }
1090
+ };
58
1091
  //# sourceMappingURL=InputBoxComponent.js.map