@azure/communication-react 1.5.1-alpha-202306030013 → 1.5.1-alpha-202306070014

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 (58) hide show
  1. package/dist/communication-react.d.ts +2 -0
  2. package/dist/dist-cjs/communication-react/index.js +1534 -1519
  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/react-components/src/components/ChatMessage/ChatMessageComponentAsMessageBubble.js +5 -10
  7. package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentAsMessageBubble.js.map +1 -1
  8. package/dist/dist-esm/react-components/src/components/FileCard.js +5 -5
  9. package/dist/dist-esm/react-components/src/components/FileCard.js.map +1 -1
  10. package/dist/dist-esm/react-components/src/components/FileCardGroup.d.ts +1 -0
  11. package/dist/dist-esm/react-components/src/components/FileCardGroup.js +2 -2
  12. package/dist/dist-esm/react-components/src/components/FileCardGroup.js.map +1 -1
  13. package/dist/dist-esm/react-components/src/components/FileDownloadCards.d.ts +1 -0
  14. package/dist/dist-esm/react-components/src/components/FileDownloadCards.js +17 -7
  15. package/dist/dist-esm/react-components/src/components/FileDownloadCards.js.map +1 -1
  16. package/dist/dist-esm/react-components/src/components/FileUploadCards.js +1 -3
  17. package/dist/dist-esm/react-components/src/components/FileUploadCards.js.map +1 -1
  18. package/dist/dist-esm/react-components/src/components/InputBoxComponent.js +40 -1357
  19. package/dist/dist-esm/react-components/src/components/InputBoxComponent.js.map +1 -1
  20. package/dist/dist-esm/react-components/src/components/MessageThread.d.ts +2 -0
  21. package/dist/dist-esm/react-components/src/components/MessageThread.js.map +1 -1
  22. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/TextFieldWithMention.d.ts +41 -0
  23. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/TextFieldWithMention.js +554 -0
  24. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/TextFieldWithMention.js.map +1 -0
  25. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/mentionTagUtils.d.ts +167 -0
  26. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/mentionTagUtils.js +780 -0
  27. package/dist/dist-esm/react-components/src/components/TextFieldWithMention/mentionTagUtils.js.map +1 -0
  28. package/dist/dist-esm/react-components/src/components/utils.d.ts +14 -0
  29. package/dist/dist-esm/react-components/src/components/utils.js +22 -0
  30. package/dist/dist-esm/react-components/src/components/utils.js.map +1 -1
  31. package/dist/dist-esm/react-components/src/localization/locales/de-DE/strings.json +2 -1
  32. package/dist/dist-esm/react-components/src/localization/locales/en-GB/strings.json +2 -1
  33. package/dist/dist-esm/react-components/src/localization/locales/en-US/strings.json +2 -1
  34. package/dist/dist-esm/react-components/src/localization/locales/es-ES/strings.json +2 -1
  35. package/dist/dist-esm/react-components/src/localization/locales/fr-FR/strings.json +2 -1
  36. package/dist/dist-esm/react-components/src/localization/locales/it-IT/strings.json +2 -1
  37. package/dist/dist-esm/react-components/src/localization/locales/ja-JP/strings.json +2 -1
  38. package/dist/dist-esm/react-components/src/localization/locales/ko-KR/strings.json +2 -1
  39. package/dist/dist-esm/react-components/src/localization/locales/nl-NL/strings.json +2 -1
  40. package/dist/dist-esm/react-components/src/localization/locales/pt-BR/strings.json +2 -1
  41. package/dist/dist-esm/react-components/src/localization/locales/ru-RU/strings.json +2 -1
  42. package/dist/dist-esm/react-components/src/localization/locales/tr-TR/strings.json +2 -1
  43. package/dist/dist-esm/react-components/src/localization/locales/zh-CN/strings.json +2 -1
  44. package/dist/dist-esm/react-components/src/localization/locales/zh-TW/strings.json +2 -1
  45. package/dist/dist-esm/react-composites/src/composites/localization/locales/de-DE/strings.json +2 -1
  46. package/dist/dist-esm/react-composites/src/composites/localization/locales/en-GB/strings.json +2 -1
  47. package/dist/dist-esm/react-composites/src/composites/localization/locales/es-ES/strings.json +2 -1
  48. package/dist/dist-esm/react-composites/src/composites/localization/locales/fr-FR/strings.json +2 -1
  49. package/dist/dist-esm/react-composites/src/composites/localization/locales/it-IT/strings.json +2 -1
  50. package/dist/dist-esm/react-composites/src/composites/localization/locales/ja-JP/strings.json +2 -1
  51. package/dist/dist-esm/react-composites/src/composites/localization/locales/ko-KR/strings.json +2 -1
  52. package/dist/dist-esm/react-composites/src/composites/localization/locales/nl-NL/strings.json +2 -1
  53. package/dist/dist-esm/react-composites/src/composites/localization/locales/pt-BR/strings.json +2 -1
  54. package/dist/dist-esm/react-composites/src/composites/localization/locales/ru-RU/strings.json +2 -1
  55. package/dist/dist-esm/react-composites/src/composites/localization/locales/tr-TR/strings.json +2 -1
  56. package/dist/dist-esm/react-composites/src/composites/localization/locales/zh-CN/strings.json +2 -1
  57. package/dist/dist-esm/react-composites/src/composites/localization/locales/zh-TW/strings.json +2 -1
  58. package/package.json +8 -8
@@ -0,0 +1,780 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT license.
3
+ const MSFT_MENTION_TAG = 'msft-mention';
4
+ /**
5
+ * Get validated value for index between min and max values. If currentValue is not defined, -1 will be used instead.
6
+ *
7
+ * @private
8
+ * @param props - Props for finding a valid index in range.
9
+ * @returns Valid index in the range.
10
+ */
11
+ export const getValidatedIndexInRange = (props) => {
12
+ const { min, max, currentValue } = props;
13
+ let updatedValue = currentValue !== null && currentValue !== void 0 ? currentValue : -1;
14
+ updatedValue = Math.max(min, updatedValue);
15
+ updatedValue = Math.min(updatedValue, max);
16
+ return updatedValue;
17
+ };
18
+ /**
19
+ * Find mention tag for selection if exists.
20
+ *
21
+ * @private
22
+ * @param tags - Existing list of tags.
23
+ * @param selection - Selection index.
24
+ * @returns Mention tag if exists, otherwise undefined.
25
+ */
26
+ export const findMentionTagForSelection = (tags, selection) => {
27
+ let mentionTag = undefined;
28
+ tags.every((tag) => {
29
+ const closingTagInfo = getTagClosingTagInfo(tag);
30
+ if (tag.plainTextBeginIndex !== undefined && tag.plainTextBeginIndex > selection) {
31
+ // no need to check further as the selection is before the tag
32
+ return false;
33
+ }
34
+ else if (tag.plainTextBeginIndex !== undefined &&
35
+ tag.plainTextBeginIndex <= selection &&
36
+ selection <= closingTagInfo.plainTextEndIndex) {
37
+ // no need to check if tag doesn't contain selection
38
+ if (tag.subTags !== undefined && tag.subTags.length !== 0) {
39
+ const selectedTag = findMentionTagForSelection(tag.subTags, selection);
40
+ if (selectedTag !== undefined) {
41
+ mentionTag = selectedTag;
42
+ return false;
43
+ }
44
+ }
45
+ else if (tag.tagType === MSFT_MENTION_TAG) {
46
+ mentionTag = tag;
47
+ return false;
48
+ }
49
+ }
50
+ return true;
51
+ });
52
+ return mentionTag;
53
+ };
54
+ /**
55
+ * Get the indices of the word for the selection.
56
+ * @private
57
+ *
58
+ */
59
+ export const rangeOfWordInSelection = ({ textInput, selectionStart, selectionEnd, tag }) => {
60
+ var _a;
61
+ if (tag.plainTextBeginIndex === undefined) {
62
+ return { start: selectionStart, end: selectionEnd === undefined ? selectionStart : selectionEnd };
63
+ }
64
+ // Look at start word index and optionally end word index.
65
+ // Select combination of the two and return the range.
66
+ let start = selectionStart;
67
+ let end = selectionEnd === undefined ? selectionStart : selectionEnd;
68
+ const firstWordStartIndex = textInput.lastIndexOf(' ', selectionStart);
69
+ if (firstWordStartIndex === tag.plainTextBeginIndex) {
70
+ start = firstWordStartIndex;
71
+ }
72
+ else {
73
+ start = Math.max(firstWordStartIndex + 1, tag.plainTextBeginIndex);
74
+ }
75
+ const firstWordEndIndex = textInput.indexOf(' ', selectionStart);
76
+ end = Math.max(firstWordEndIndex + 1, (_a = tag.plainTextEndIndex) !== null && _a !== void 0 ? _a : firstWordEndIndex + 1);
77
+ if (selectionEnd !== undefined && tag.plainTextEndIndex !== undefined) {
78
+ const lastWordEndIndex = textInput.indexOf(' ', selectionEnd);
79
+ end = Math.max(lastWordEndIndex > -1 ? lastWordEndIndex : tag.plainTextEndIndex, selectionEnd);
80
+ }
81
+ return { start, end };
82
+ };
83
+ /**
84
+ * Find a new the selection index.
85
+ *
86
+ * @private
87
+ * @param props - Props for finding new selection index for mention.
88
+ * @returns New selection index if it is inside of a mention tag, otherwise the current selection.
89
+ */
90
+ export const findNewSelectionIndexForMention = (props) => {
91
+ var _a;
92
+ const { tag, textValue, currentSelectionIndex, previousSelectionIndex } = props;
93
+ // check if this is a mention tag and selection should be updated
94
+ if (tag.tagType !== MSFT_MENTION_TAG ||
95
+ tag.plainTextBeginIndex === undefined ||
96
+ currentSelectionIndex === previousSelectionIndex ||
97
+ tag.plainTextEndIndex === undefined) {
98
+ return currentSelectionIndex;
99
+ }
100
+ let spaceIndex = 0;
101
+ if (currentSelectionIndex <= previousSelectionIndex) {
102
+ // the cursor is moved to the left, find the last index before the cursor
103
+ spaceIndex = textValue.lastIndexOf(' ', currentSelectionIndex !== null && currentSelectionIndex !== void 0 ? currentSelectionIndex : 0);
104
+ if (spaceIndex === -1) {
105
+ // no space before the selection, use the beginning of the tag
106
+ spaceIndex = tag.plainTextBeginIndex;
107
+ }
108
+ }
109
+ else {
110
+ // the cursor is moved to the right, find the fist index after the cursor
111
+ spaceIndex = textValue.indexOf(' ', currentSelectionIndex !== null && currentSelectionIndex !== void 0 ? currentSelectionIndex : 0);
112
+ if (spaceIndex === -1) {
113
+ // no space after the selection, use the end of the tag
114
+ spaceIndex = (_a = tag.plainTextEndIndex) !== null && _a !== void 0 ? _a : tag.plainTextBeginIndex;
115
+ }
116
+ }
117
+ spaceIndex = Math.max(tag.plainTextBeginIndex, spaceIndex);
118
+ spaceIndex = Math.min(tag.plainTextEndIndex, spaceIndex);
119
+ return spaceIndex;
120
+ };
121
+ /**
122
+ * Handle mention tag edit and by word deleting
123
+ *
124
+ * @private
125
+ * @param props - Props for mention update HTML function.
126
+ * @returns Updated texts and indexes.
127
+ */
128
+ const handleMentionTagUpdate = (props) => {
129
+ const { htmlText, oldPlainText, change, tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength } = props;
130
+ let processedChange = props.processedChange;
131
+ let lastProcessedHTMLIndex = props.lastProcessedHTMLIndex;
132
+ if (tag.tagType !== MSFT_MENTION_TAG || tag.plainTextBeginIndex === undefined) {
133
+ // not a mention tag
134
+ return {
135
+ result: '',
136
+ updatedChange: processedChange,
137
+ htmlIndex: lastProcessedHTMLIndex,
138
+ plainTextSelectionEndIndex: undefined
139
+ };
140
+ }
141
+ let result = '';
142
+ let plainTextSelectionEndIndex;
143
+ let rangeStart;
144
+ let rangeEnd;
145
+ // check if space symbol is handled in case if string looks like '<1 2 3>'
146
+ let isSpaceLengthHandled = false;
147
+ rangeStart = oldPlainText.lastIndexOf(' ', startIndex);
148
+ if (rangeStart !== -1 && rangeStart !== undefined && rangeStart > tag.plainTextBeginIndex) {
149
+ isSpaceLengthHandled = true;
150
+ }
151
+ rangeEnd = oldPlainText.indexOf(' ', oldPlainTextEndIndex);
152
+ if (rangeEnd === -1 || rangeEnd === undefined) {
153
+ // check if space symbol is not found
154
+ rangeEnd = plainTextEndIndex;
155
+ }
156
+ else if (!isSpaceLengthHandled) {
157
+ // +1 to include the space symbol
158
+ rangeEnd += 1;
159
+ }
160
+ isSpaceLengthHandled = true;
161
+ if (rangeStart === -1 || rangeStart === undefined || rangeStart < tag.plainTextBeginIndex) {
162
+ // rangeStart should be at least equal to tag.plainTextBeginIndex
163
+ rangeStart = tag.plainTextBeginIndex;
164
+ }
165
+ if (rangeEnd > plainTextEndIndex) {
166
+ // rangeEnd should be at most equal to plainTextEndIndex
167
+ rangeEnd = plainTextEndIndex;
168
+ }
169
+ if (rangeStart === tag.plainTextBeginIndex && rangeEnd === plainTextEndIndex) {
170
+ // the whole tag should be removed
171
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
172
+ plainTextSelectionEndIndex = tag.plainTextBeginIndex + processedChange.length;
173
+ processedChange = '';
174
+ lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
175
+ }
176
+ else {
177
+ // only part of the tag should be removed
178
+ let startChangeDiff = 0;
179
+ let endChangeDiff = 0;
180
+ // need to check only rangeStart > tag.plainTextBeginIndex as when rangeStart === tag.plainTextBeginIndex startChangeDiff = 0 and mentionTagLength shouldn't be subtracted
181
+ if (rangeStart > tag.plainTextBeginIndex) {
182
+ startChangeDiff = rangeStart - tag.plainTextBeginIndex - mentionTagLength;
183
+ }
184
+ endChangeDiff = rangeEnd - tag.plainTextBeginIndex - mentionTagLength;
185
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff);
186
+ if (startIndex < tag.plainTextBeginIndex) {
187
+ // if the change is before the tag, the selection should start from startIndex (rangeStart will be equal to tag.plainTextBeginIndex)
188
+ plainTextSelectionEndIndex = startIndex + change.length;
189
+ }
190
+ else {
191
+ // if the change is inside the tag, the selection should start with rangeStart
192
+ plainTextSelectionEndIndex = rangeStart + processedChange.length;
193
+ }
194
+ lastProcessedHTMLIndex = tag.openTagIndex + tag.openTagBody.length + endChangeDiff;
195
+ // processed change should not be changed as it should be added after the tag
196
+ }
197
+ return { result, updatedChange: processedChange, htmlIndex: lastProcessedHTMLIndex, plainTextSelectionEndIndex };
198
+ };
199
+ /**
200
+ * Get closing tag information if exists otherwise return information as for self closing tag
201
+ *
202
+ * @private
203
+ * @param tag - Tag data.
204
+ * @returns Closing tag information for the provided tag.
205
+ */
206
+ const getTagClosingTagInfo = (tag) => {
207
+ let plainTextEndIndex = 0;
208
+ let closeTagIdx = 0;
209
+ let closeTagLength = 0;
210
+ if (tag.plainTextEndIndex !== undefined && tag.closingTagIndex !== undefined) {
211
+ // close tag exists
212
+ plainTextEndIndex = tag.plainTextEndIndex;
213
+ closeTagIdx = tag.closingTagIndex;
214
+ // tag.tagType.length + </>
215
+ closeTagLength = tag.tagType.length + 3;
216
+ }
217
+ else if (tag.plainTextBeginIndex !== undefined) {
218
+ // no close tag
219
+ plainTextEndIndex = tag.plainTextBeginIndex;
220
+ closeTagIdx = tag.openTagIndex + tag.openTagBody.length;
221
+ closeTagLength = 0;
222
+ }
223
+ return { plainTextEndIndex, closeTagIdx, closeTagLength };
224
+ };
225
+ /**
226
+ * Go through the text and update it with the changed text
227
+ *
228
+ * @private
229
+ * @param props - Props for update HTML function.
230
+ * @returns Updated HTML and selection index if the selection index should be set.
231
+ */
232
+ export const updateHTML = (props) => {
233
+ const { htmlText, oldPlainText, newPlainText, tags, startIndex, oldPlainTextEndIndex, change, mentionTrigger } = props;
234
+ if (tags.length === 0 || (startIndex === 0 && oldPlainTextEndIndex === oldPlainText.length - 1)) {
235
+ // no tags added yet or the whole text is changed
236
+ return { updatedHTML: newPlainText, updatedSelectionIndex: undefined };
237
+ }
238
+ let result = '';
239
+ let lastProcessedHTMLIndex = 0;
240
+ // the value can be updated with empty string when the change covers more than 1 place (tag + before or after the tag)
241
+ // in this case change won't be added as part of the tag
242
+ // 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
243
+ // 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
244
+ // e.g.: change is on the beginning of the tag => change will be added before the tag
245
+ // 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
246
+ let processedChange = change;
247
+ // end tag plain text index of the last processed tag
248
+ let lastProcessedPlainTextTagEndIndex = 0;
249
+ // as some tags/text can be removed fully, selection should be updated correctly
250
+ let changeNewEndIndex;
251
+ for (let i = 0; i < tags.length; i++) {
252
+ const tag = tags[i];
253
+ if (tag.plainTextBeginIndex === undefined) {
254
+ continue;
255
+ }
256
+ // all plain text indexes includes trigger length for the mention that shouldn't be included in
257
+ // htmlText.substring because html strings don't include the trigger
258
+ // mentionTagLength will be set only for mention tag, otherwise should be 0
259
+ let mentionTagLength = 0;
260
+ let isMentionTag = false;
261
+ if (tag.tagType === MSFT_MENTION_TAG) {
262
+ mentionTagLength = mentionTrigger.length;
263
+ isMentionTag = true;
264
+ }
265
+ if (startIndex <= tag.plainTextBeginIndex) {
266
+ // change start is before the open tag
267
+ // Math.max(lastProcessedPlainTextTagEndIndex, startIndex) is used as startIndex may not be in [[previous tag].plainTextEndIndex - tag.plainTextBeginIndex] range
268
+ const startChangeDiff = tag.plainTextBeginIndex - Math.max(lastProcessedPlainTextTagEndIndex, startIndex);
269
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex - startChangeDiff) + processedChange;
270
+ processedChange = '';
271
+ if (oldPlainTextEndIndex <= tag.plainTextBeginIndex) {
272
+ // the whole change is before tag start
273
+ // mentionTag length can be ignored here as the change is before the tag
274
+ const endChangeDiff = tag.plainTextBeginIndex - oldPlainTextEndIndex;
275
+ lastProcessedHTMLIndex = tag.openTagIndex - endChangeDiff;
276
+ // the change is handled; exit
277
+ break;
278
+ }
279
+ else {
280
+ // change continues in the tag
281
+ lastProcessedHTMLIndex = tag.openTagIndex;
282
+ // proceed to the next check
283
+ }
284
+ }
285
+ const closingTagInfo = getTagClosingTagInfo(tag);
286
+ if (startIndex <= closingTagInfo.plainTextEndIndex) {
287
+ // change started before the end tag
288
+ if (startIndex <= tag.plainTextBeginIndex && oldPlainTextEndIndex === closingTagInfo.plainTextEndIndex) {
289
+ // the change is a tag or starts before the tag
290
+ // tag should be removed, no matter if there are sub-tags
291
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
292
+ processedChange = '';
293
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
294
+ // the change is handled; exit
295
+ break;
296
+ }
297
+ else if (startIndex >= tag.plainTextBeginIndex && oldPlainTextEndIndex <= closingTagInfo.plainTextEndIndex) {
298
+ // the change is between the tag
299
+ if (isMentionTag) {
300
+ if (change !== '') {
301
+ if (startIndex !== tag.plainTextBeginIndex && startIndex !== closingTagInfo.plainTextEndIndex) {
302
+ // mention tag should be deleted when user tries to edit it in the middle
303
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
304
+ changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
305
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
306
+ }
307
+ else if (startIndex === tag.plainTextBeginIndex) {
308
+ // non empty change at the beginning of the mention tag to be added before the mention tag
309
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
310
+ changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
311
+ lastProcessedHTMLIndex = tag.openTagIndex;
312
+ }
313
+ else if (startIndex === closingTagInfo.plainTextEndIndex) {
314
+ // non empty change at the end of the mention tag to be added after the mention tag
315
+ result +=
316
+ htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength) +
317
+ processedChange;
318
+ changeNewEndIndex = closingTagInfo.plainTextEndIndex + processedChange.length;
319
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
320
+ }
321
+ processedChange = '';
322
+ }
323
+ else {
324
+ const updateMentionTagResult = handleMentionTagUpdate({
325
+ htmlText,
326
+ oldPlainText,
327
+ lastProcessedHTMLIndex,
328
+ processedChange,
329
+ change,
330
+ tag,
331
+ closeTagIdx: closingTagInfo.closeTagIdx,
332
+ closeTagLength: closingTagInfo.closeTagLength,
333
+ plainTextEndIndex: closingTagInfo.plainTextEndIndex,
334
+ startIndex,
335
+ oldPlainTextEndIndex,
336
+ mentionTagLength
337
+ });
338
+ result += updateMentionTagResult.result;
339
+ changeNewEndIndex = updateMentionTagResult.plainTextSelectionEndIndex;
340
+ processedChange = updateMentionTagResult.updatedChange;
341
+ lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
342
+ }
343
+ }
344
+ else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
345
+ // with subtags
346
+ const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
347
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
348
+ const updatedContent = updateHTML({
349
+ htmlText: tag.content,
350
+ oldPlainText,
351
+ newPlainText,
352
+ tags: tag.subTags,
353
+ startIndex,
354
+ oldPlainTextEndIndex,
355
+ change: processedChange,
356
+ mentionTrigger
357
+ });
358
+ result += stringBefore + updatedContent.updatedHTML;
359
+ changeNewEndIndex = updatedContent.updatedSelectionIndex;
360
+ }
361
+ else {
362
+ // no subtags
363
+ const startChangeDiff = startIndex - tag.plainTextBeginIndex;
364
+ result +=
365
+ htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff) +
366
+ processedChange;
367
+ processedChange = '';
368
+ if (oldPlainTextEndIndex < closingTagInfo.plainTextEndIndex) {
369
+ const endChangeDiff = oldPlainTextEndIndex - tag.plainTextBeginIndex;
370
+ lastProcessedHTMLIndex = tag.openTagIndex + tag.openTagBody.length + endChangeDiff;
371
+ }
372
+ else if (oldPlainTextEndIndex === closingTagInfo.plainTextEndIndex) {
373
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
374
+ }
375
+ }
376
+ // the change is handled; exit
377
+ break;
378
+ }
379
+ else if (startIndex > tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
380
+ // the change started in the tag but finishes somewhere further
381
+ const startChangeDiff = startIndex - tag.plainTextBeginIndex - mentionTagLength;
382
+ if (isMentionTag) {
383
+ const updateMentionTagResult = handleMentionTagUpdate({
384
+ htmlText,
385
+ oldPlainText,
386
+ lastProcessedHTMLIndex,
387
+ processedChange: '',
388
+ change,
389
+ tag,
390
+ closeTagIdx: closingTagInfo.closeTagIdx,
391
+ closeTagLength: closingTagInfo.closeTagLength,
392
+ plainTextEndIndex: closingTagInfo.plainTextEndIndex,
393
+ startIndex,
394
+ oldPlainTextEndIndex,
395
+ mentionTagLength
396
+ });
397
+ result += updateMentionTagResult.result;
398
+ lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
399
+ // no need to handle plainTextSelectionEndIndex as the change will be added later
400
+ }
401
+ else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
402
+ // with subtags
403
+ const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
404
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
405
+ const updatedContent = updateHTML({
406
+ htmlText: tag.content,
407
+ oldPlainText,
408
+ newPlainText,
409
+ tags: tag.subTags,
410
+ startIndex,
411
+ oldPlainTextEndIndex,
412
+ change: '',
413
+ mentionTrigger
414
+ });
415
+ result += stringBefore + updatedContent.updatedHTML;
416
+ }
417
+ else {
418
+ // no subtags
419
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff);
420
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
421
+ }
422
+ // proceed with the next calculations
423
+ }
424
+ else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
425
+ // the change starts before the tag and finishes after it
426
+ // tag should be removed, no matter if there are subtags
427
+ // no need to save anything between lastProcessedHTMLIndex and closeTagIdx + closeTagLength
428
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
429
+ // proceed with the next calculations
430
+ }
431
+ else if (startIndex === tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
432
+ // the change starts in the tag and finishes after it
433
+ // tag should be removed, no matter if there are subtags
434
+ result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex);
435
+ // processedChange shouldn't be updated as it will be added after the tag
436
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
437
+ // proceed with the next calculations
438
+ }
439
+ else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex < closingTagInfo.plainTextEndIndex) {
440
+ // the change starts before the tag and ends in a tag
441
+ if (isMentionTag) {
442
+ // mention tag
443
+ const updateMentionTagResult = handleMentionTagUpdate({
444
+ htmlText,
445
+ oldPlainText,
446
+ lastProcessedHTMLIndex,
447
+ processedChange: '',
448
+ change,
449
+ tag,
450
+ closeTagIdx: closingTagInfo.closeTagIdx,
451
+ closeTagLength: closingTagInfo.closeTagLength,
452
+ plainTextEndIndex: closingTagInfo.plainTextEndIndex,
453
+ startIndex,
454
+ oldPlainTextEndIndex,
455
+ mentionTagLength
456
+ });
457
+ changeNewEndIndex = updateMentionTagResult.plainTextSelectionEndIndex;
458
+ result += updateMentionTagResult.result;
459
+ lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
460
+ }
461
+ else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
462
+ // with subtags
463
+ const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
464
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
465
+ const updatedContent = updateHTML({
466
+ htmlText: tag.content,
467
+ oldPlainText,
468
+ newPlainText,
469
+ tags: tag.subTags,
470
+ startIndex,
471
+ oldPlainTextEndIndex,
472
+ change: processedChange,
473
+ mentionTrigger
474
+ });
475
+ processedChange = '';
476
+ result += stringBefore + updatedContent.updatedHTML;
477
+ }
478
+ else {
479
+ // no subtags
480
+ result +=
481
+ htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length) + processedChange;
482
+ processedChange = '';
483
+ // oldPlainTextEndIndex already includes mentionTag length
484
+ const endChangeDiff = closingTagInfo.plainTextEndIndex - oldPlainTextEndIndex;
485
+ // as change may be before the end of the tag, we need to add the rest of the tag
486
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx - endChangeDiff;
487
+ }
488
+ // the change is handled; exit
489
+ break;
490
+ }
491
+ lastProcessedPlainTextTagEndIndex = closingTagInfo.plainTextEndIndex;
492
+ }
493
+ if (i === tags.length - 1 && oldPlainTextEndIndex >= closingTagInfo.plainTextEndIndex) {
494
+ // the last tag should handle the end of the change if needed
495
+ // oldPlainTextEndIndex already includes mentionTag length
496
+ const endChangeDiff = oldPlainTextEndIndex - closingTagInfo.plainTextEndIndex;
497
+ if (startIndex >= closingTagInfo.plainTextEndIndex) {
498
+ const startChangeDiff = startIndex - closingTagInfo.plainTextEndIndex;
499
+ result +=
500
+ htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength + startChangeDiff) + processedChange;
501
+ }
502
+ else {
503
+ result +=
504
+ htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength) +
505
+ processedChange;
506
+ }
507
+ processedChange = '';
508
+ lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength + endChangeDiff;
509
+ // the change is handled; exit
510
+ // break is not required here as this is the last element but added for consistency
511
+ break;
512
+ }
513
+ }
514
+ if (lastProcessedHTMLIndex < htmlText.length) {
515
+ // add the rest of the html string
516
+ result += htmlText.substring(lastProcessedHTMLIndex);
517
+ }
518
+ return { updatedHTML: result, updatedSelectionIndex: changeNewEndIndex };
519
+ };
520
+ /**
521
+ * Given the oldText and newText, find the start index, old end index and new end index for the changes
522
+ *
523
+ * @private
524
+ * @param props - Props for finding stings diff indexes function.
525
+ * @returns Indexes for change start and ends in new and old texts. The old and new end indexes are exclusive.
526
+ */
527
+ export const findStringsDiffIndexes = (props) => {
528
+ const { oldText, newText, previousSelectionStart, previousSelectionEnd, currentSelectionStart, currentSelectionEnd } = props;
529
+ const newTextLength = newText.length;
530
+ const oldTextLength = oldText.length;
531
+ // let changeStart = 0;
532
+ let newChangeEnd = newTextLength;
533
+ let oldChangeEnd = oldTextLength;
534
+ const previousSelectionStartValue = previousSelectionStart > -1 ? previousSelectionStart : oldTextLength;
535
+ const previousSelectionEndValue = previousSelectionEnd > -1 ? previousSelectionEnd : oldTextLength;
536
+ const currentSelectionStartValue = currentSelectionStart > -1 ? currentSelectionStart : newTextLength;
537
+ const currentSelectionEndValue = currentSelectionEnd > -1 ? currentSelectionEnd : newTextLength;
538
+ const changeStart = Math.min(previousSelectionStartValue, previousSelectionEndValue, currentSelectionStartValue, currentSelectionEndValue, newTextLength, oldTextLength);
539
+ if (oldTextLength < newTextLength) {
540
+ //insert or replacement
541
+ if (oldTextLength === changeStart) {
542
+ // when change was at the end of string
543
+ // change is found
544
+ newChangeEnd = newTextLength;
545
+ oldChangeEnd = oldTextLength;
546
+ }
547
+ else {
548
+ for (let i = 1; i < newTextLength && oldTextLength - i >= changeStart; i++) {
549
+ newChangeEnd = newTextLength - i - 1;
550
+ oldChangeEnd = oldTextLength - i - 1;
551
+ if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
552
+ // change is found
553
+ break;
554
+ }
555
+ }
556
+ // make indexes exclusive
557
+ newChangeEnd += 1;
558
+ oldChangeEnd += 1;
559
+ }
560
+ }
561
+ else if (oldTextLength > newTextLength) {
562
+ //deletion or replacement
563
+ if (newTextLength === changeStart) {
564
+ // when change was at the end of string
565
+ // change is found
566
+ newChangeEnd = newTextLength;
567
+ oldChangeEnd = oldTextLength;
568
+ }
569
+ else {
570
+ for (let i = 1; i < oldTextLength && newTextLength - i >= changeStart; i++) {
571
+ newChangeEnd = newTextLength - i - 1;
572
+ oldChangeEnd = oldTextLength - i - 1;
573
+ if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
574
+ // change is found
575
+ break;
576
+ }
577
+ }
578
+ // make indexes exclusive
579
+ newChangeEnd += 1;
580
+ oldChangeEnd += 1;
581
+ }
582
+ }
583
+ else {
584
+ // replacement
585
+ for (let i = 1; i < oldTextLength && oldTextLength - i >= changeStart; i++) {
586
+ newChangeEnd = newTextLength - i - 1;
587
+ oldChangeEnd = oldTextLength - i - 1;
588
+ if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
589
+ // change is found
590
+ break;
591
+ }
592
+ }
593
+ // make indexes exclusive if they aren't equal to the length of the string
594
+ if (newChangeEnd !== newText.length) {
595
+ newChangeEnd += 1;
596
+ }
597
+ if (oldChangeEnd !== oldText.length) {
598
+ oldChangeEnd += 1;
599
+ }
600
+ }
601
+ return { changeStart, oldChangeEnd, newChangeEnd };
602
+ };
603
+ /**
604
+ * Get the html string for the mention suggestion.
605
+ *
606
+ * @private
607
+ * @param suggestion - The mention suggestion.
608
+ * @param localeStrings - The locale strings.
609
+ * @returns The html string for the mention suggestion.
610
+ */
611
+ export const htmlStringForMentionSuggestion = (suggestion, localeStrings) => {
612
+ const idHTML = ' id ="' + suggestion.id + '"';
613
+ const displayTextHTML = ' displayText ="' + suggestion.displayText + '"';
614
+ const displayText = getDisplayNameForMentionSuggestion(suggestion, localeStrings);
615
+ return '<' + MSFT_MENTION_TAG + idHTML + displayTextHTML + '>' + displayText + '</' + MSFT_MENTION_TAG + '>';
616
+ };
617
+ /**
618
+ * Get display name for the mention suggestion.
619
+ *
620
+ * @private
621
+ *
622
+ * @param suggestion - The mention suggestion.
623
+ * @param localeStrings - The locale strings.
624
+ * @returns The display name for the mention suggestion or display name placeholder if display name is empty.
625
+ */
626
+ export const getDisplayNameForMentionSuggestion = (suggestion, localeStrings) => {
627
+ const displayNamePlaceholder = localeStrings.participantItem.displayNamePlaceholder;
628
+ return suggestion.displayText !== '' ? suggestion.displayText : displayNamePlaceholder !== null && displayNamePlaceholder !== void 0 ? displayNamePlaceholder : '';
629
+ };
630
+ /**
631
+ * Parse the text and return the tags and the plain text in one go
632
+ * @private
633
+ * @param text - The text to parse for HTML tags
634
+ * @param trigger The trigger to show for the mention tag in plain text
635
+ *
636
+ * @returns An array of tags and the plain text representation
637
+ */
638
+ export const textToTagParser = (text, trigger) => {
639
+ var _a, _b;
640
+ const tags = []; // Tags passed back to the caller
641
+ const tagParseStack = []; // Local stack to use while parsing
642
+ let plainTextRepresentation = '';
643
+ let parseIndex = 0;
644
+ while (parseIndex < text.length) {
645
+ const foundHtmlTag = findNextHtmlTag(text, parseIndex);
646
+ if (!foundHtmlTag) {
647
+ if (parseIndex !== 0) {
648
+ // Add the remaining text to the plain text representation
649
+ plainTextRepresentation += text.substring(parseIndex);
650
+ }
651
+ else {
652
+ plainTextRepresentation = text;
653
+ }
654
+ break;
655
+ }
656
+ if (foundHtmlTag.type === 'open' || foundHtmlTag.type === 'self-closing') {
657
+ const nextTag = parseOpenTag(foundHtmlTag.content, foundHtmlTag.startIdx);
658
+ // Add the plain text between the last tag and this one found
659
+ plainTextRepresentation += text.substring(parseIndex, foundHtmlTag.startIdx);
660
+ nextTag.plainTextBeginIndex = plainTextRepresentation.length;
661
+ if (foundHtmlTag.type === 'open') {
662
+ tagParseStack.push(nextTag);
663
+ }
664
+ else {
665
+ nextTag.content = '';
666
+ nextTag.plainTextBeginIndex = plainTextRepresentation.length;
667
+ nextTag.plainTextEndIndex = plainTextRepresentation.length;
668
+ addTag(nextTag, tagParseStack, tags);
669
+ }
670
+ }
671
+ if (foundHtmlTag.type === 'close') {
672
+ const currentOpenTag = tagParseStack.pop();
673
+ const closeTagType = foundHtmlTag.content.substring(2, foundHtmlTag.content.length - 1).toLowerCase();
674
+ if (currentOpenTag && currentOpenTag.tagType === closeTagType) {
675
+ // Tag startIdx is absolute to the text. This is updated later to be relative to the parent tag
676
+ currentOpenTag.content = text.substring(currentOpenTag.openTagIndex + currentOpenTag.openTagBody.length, foundHtmlTag.startIdx);
677
+ // Insert the plain text pieces for the sub tags
678
+ if (currentOpenTag.tagType === MSFT_MENTION_TAG) {
679
+ plainTextRepresentation =
680
+ plainTextRepresentation.slice(0, currentOpenTag.plainTextBeginIndex) +
681
+ trigger +
682
+ plainTextRepresentation.slice(currentOpenTag.plainTextBeginIndex);
683
+ }
684
+ if (!currentOpenTag.subTags) {
685
+ plainTextRepresentation += currentOpenTag.content;
686
+ }
687
+ else if (currentOpenTag.subTags.length > 0) {
688
+ // Add text after the last tag
689
+ const lastSubTag = currentOpenTag.subTags[currentOpenTag.subTags.length - 1];
690
+ const startOfRemainingText = ((_a = lastSubTag.closingTagIndex) !== null && _a !== void 0 ? _a : lastSubTag.openTagIndex) + lastSubTag.tagType.length + 3;
691
+ const trailingText = currentOpenTag.content.substring(startOfRemainingText);
692
+ plainTextRepresentation += trailingText;
693
+ }
694
+ currentOpenTag.plainTextEndIndex = plainTextRepresentation.length;
695
+ addTag(currentOpenTag, tagParseStack, tags);
696
+ }
697
+ else {
698
+ throw new Error('Unexpected close tag found. Got "' +
699
+ closeTagType +
700
+ '" but expected "' +
701
+ ((_b = tagParseStack[tagParseStack.length - 1]) === null || _b === void 0 ? void 0 : _b.tagType) +
702
+ '"');
703
+ }
704
+ }
705
+ // Update parsing index; move past the end of the close tag
706
+ parseIndex = foundHtmlTag.startIdx + foundHtmlTag.content.length;
707
+ } // While parseIndex < text.length loop
708
+ return { tags, plainText: plainTextRepresentation };
709
+ };
710
+ const parseOpenTag = (tag, startIdx) => {
711
+ const tagType = tag
712
+ .substring(1, tag.length - 1)
713
+ .split(' ')[0]
714
+ .toLowerCase()
715
+ .replace('/', '');
716
+ return {
717
+ tagType,
718
+ openTagIndex: startIdx,
719
+ openTagBody: tag
720
+ };
721
+ };
722
+ const findNextHtmlTag = (text, startIndex) => {
723
+ const tagStartIndex = text.indexOf('<', startIndex);
724
+ if (tagStartIndex === -1) {
725
+ // No more tags
726
+ return undefined;
727
+ }
728
+ const tagEndIndex = text.indexOf('>', tagStartIndex);
729
+ if (tagEndIndex === -1) {
730
+ // No close tag
731
+ return undefined;
732
+ }
733
+ const tag = text.substring(tagStartIndex, tagEndIndex + 1);
734
+ let type = 'open';
735
+ if (tag[1] === '/') {
736
+ type = 'close';
737
+ }
738
+ else if (tag[tag.length - 2] === '/') {
739
+ type = 'self-closing';
740
+ }
741
+ return {
742
+ content: tag,
743
+ startIdx: tagStartIndex,
744
+ type
745
+ };
746
+ };
747
+ const addTag = (tag, parseStack, tags) => {
748
+ var _a;
749
+ // Add as sub-tag to the parent stack tag, if there is one
750
+ const parentTag = parseStack[parseStack.length - 1];
751
+ if (parentTag) {
752
+ // Adjust the open tag index to be relative to the parent tag
753
+ const parentContentStartIdx = parentTag.openTagIndex + parentTag.openTagBody.length;
754
+ const relativeIdx = tag.openTagIndex - parentContentStartIdx;
755
+ tag.openTagIndex = relativeIdx;
756
+ }
757
+ if (!tag.closingTagIndex) {
758
+ // If the tag is self-closing, the close tag is the same as the open tag
759
+ if (tag.openTagBody[tag.openTagBody.length - 2] === '/') {
760
+ tag.closingTagIndex = tag.openTagIndex;
761
+ }
762
+ else {
763
+ // Otherwise, the close tag index is the open tag index + the open tag body + the content length
764
+ tag.closingTagIndex = tag.openTagIndex + tag.openTagBody.length + ((_a = tag.content) !== null && _a !== void 0 ? _a : []).length;
765
+ }
766
+ }
767
+ // Put the tag where it belongs
768
+ if (!parentTag) {
769
+ tags.push(tag);
770
+ }
771
+ else {
772
+ if (!parentTag.subTags) {
773
+ parentTag.subTags = [tag];
774
+ }
775
+ else {
776
+ parentTag.subTags.push(tag);
777
+ }
778
+ }
779
+ };
780
+ //# sourceMappingURL=mentionTagUtils.js.map