@azure/communication-react 1.5.1-alpha-202306060014 → 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.
@@ -1,117 +1,20 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT license.
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, useMemo } from 'react';
15
- /* @conditional-compile-remove(mention) */
16
- import { useLocale } from '../localization';
17
- /* @conditional-compile-remove(mention) */
18
- import { Announcer } from './Announcer';
3
+ import React, { useState, useCallback } from 'react';
19
4
  import { Stack, TextField, mergeStyles, concatStyleSets, IconButton, TooltipHost } from '@fluentui/react';
20
5
  import { isEnterKeyEventFromCompositionSession } from './utils';
21
- /* @conditional-compile-remove(mention) */
22
- import { nullToUndefined, undefinedToNull } from './utils';
23
6
  import { inputBoxStyle, inputBoxWrapperStyle, inputButtonStyle, textFieldStyle, textContainerStyle, newLineButtonsContainerStyle, inputBoxNewLineSpaceAffordance, inputButtonTooltipStyle, iconWrapperStyle } from './styles/InputBoxComponent.style';
24
- /* @conditional-compile-remove(mention) */
25
- import { Caret } from 'textarea-caret-ts';
26
7
  import { isDarkThemed } from '../theming/themeUtils';
27
8
  import { useTheme } from '../theming';
28
9
  /* @conditional-compile-remove(mention) */
29
- import { _MentionPopover } from './MentionPopover';
30
- /* @conditional-compile-remove(mention) */
31
- import { useDebouncedCallback } from 'use-debounce';
32
- /* @conditional-compile-remove(mention) */
33
- const DEFAULT_MENTION_TRIGGER = '@';
34
- /* @conditional-compile-remove(mention) */
35
- const MSFT_MENTION_TAG = 'msft-mention';
10
+ import { TextFieldWithMention } from './TextFieldWithMention/TextFieldWithMention';
36
11
  /**
37
12
  * @private
38
13
  */
39
14
  export const InputBoxComponent = (props) => {
40
- const { styles, id, 'data-ui-id': dataUiId, textValue, onChange, textFieldRef, placeholderText, onKeyDown, onEnterKeyDown, supportNewline, inputClassName, errorMessage, disabled,
41
- /* @conditional-compile-remove(mention) */
42
- mentionLookupOptions, children } = props;
43
- const inputBoxRef = useRef(null);
44
- /* @conditional-compile-remove(mention) */
45
- // Current suggestion list, provided by the callback
46
- const [mentionSuggestions, setMentionSuggestions] = useState([]);
47
- /* @conditional-compile-remove(mention) */
48
- // Current suggestion list, provided by the callback
49
- const [activeSuggestionIndex, setActiveSuggestionIndex] = useState(undefined);
50
- /* @conditional-compile-remove(mention) */
51
- // Index of the current trigger character in the text field
52
- const [currentTriggerStartIndex, setCurrentTriggerStartIndex] = useState(-1);
53
- /* @conditional-compile-remove(mention) */
54
- const [inputTextValue, setInputTextValue] = useState('');
55
- /* @conditional-compile-remove(mention) */
56
- const [tagsValue, setTagsValue] = useState([]);
57
- /* @conditional-compile-remove(mention) */
58
- // Index of the previous selection start in the text field
59
- const [selectionStartValue, setSelectionStartValue] = useState();
60
- /* @conditional-compile-remove(mention) */
61
- // Index of the previous selection end in the text field
62
- const [selectionEndValue, setSelectionEndValue] = useState();
63
- /* @conditional-compile-remove(mention) */
64
- // Boolean value to check if onMouseDown event should be handled during select as selection range
65
- // for onMouseDown event is not updated yet and the selection range for mouse click/taps will be
66
- // updated in onSelect event if needed.
67
- const [shouldHandleOnMouseDownDuringSelect, setShouldHandleOnMouseDownDuringSelect] = useState(true);
68
- /* @conditional-compile-remove(mention) */
69
- // Point of start of touch/mouse selection
70
- const [interactionStartPoint, setInteractionStartPoint] = useState();
71
- /* @conditional-compile-remove(mention) */
72
- // Target selection from mouse movement
73
- const [targetSelection, setTargetSelection] = useState();
74
- /* @conditional-compile-remove(mention) */
75
- // Caret position in the text field
76
- const [caretPosition, setCaretPosition] = useState(undefined);
77
- /* @conditional-compile-remove(mention) */
78
- // Index of where the caret is in the text field
79
- const [caretIndex, setCaretIndex] = useState(undefined);
80
- /* @conditional-compile-remove(mention) */
81
- const localeStrings = useLocale().strings;
82
- /* @conditional-compile-remove(mention) */
83
- // Set mention suggestions
84
- const updateMentionSuggestions = useCallback((suggestions) => {
85
- setMentionSuggestions(suggestions);
86
- }, [setMentionSuggestions]);
87
- /* @conditional-compile-remove(mention) */
88
- // Parse the text and get the plain text version to display in the input box
89
- useEffect(() => {
90
- const trigger = (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) || DEFAULT_MENTION_TRIGGER;
91
- const parsedHTMLData = textToTagParser(textValue, trigger);
92
- setInputTextValue(parsedHTMLData.plainText);
93
- setTagsValue(parsedHTMLData.tags);
94
- updateMentionSuggestions([]);
95
- }, [textValue, mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger, updateMentionSuggestions]);
15
+ const { styles, id, 'data-ui-id': dataUiId, textValue, onChange, textFieldRef, placeholderText, onKeyDown, onEnterKeyDown, supportNewline, inputClassName, errorMessage, disabled, children } = props;
96
16
  const mergedRootStyle = mergeStyles(inputBoxWrapperStyle, styles === null || styles === void 0 ? void 0 : styles.root);
97
17
  const mergedInputFieldStyle = mergeStyles(inputBoxStyle, inputClassName, props.inlineChildren ? {} : inputBoxNewLineSpaceAffordance);
98
- /* @conditional-compile-remove(mention) */
99
- useEffect(() => {
100
- var _a;
101
- // effect for caret index update
102
- if (caretIndex === undefined || textFieldRef === undefined || (textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === undefined) {
103
- return;
104
- }
105
- // get validated caret index between 0 and inputTextValue.length otherwise caret will be set to incorrect index
106
- const updatedCaretIndex = getValidatedIndexInRange({
107
- min: 0,
108
- max: inputTextValue.length,
109
- currentValue: caretIndex
110
- });
111
- (_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.setSelectionRange(updatedCaretIndex, updatedCaretIndex);
112
- setSelectionStartValue(updatedCaretIndex);
113
- setSelectionEndValue(updatedCaretIndex);
114
- }, [caretIndex, inputTextValue.length, textFieldRef, setSelectionStartValue, setSelectionEndValue]);
115
18
  const mergedTextContainerStyle = mergeStyles(textContainerStyle, styles === null || styles === void 0 ? void 0 : styles.textFieldContainer);
116
19
  const mergedTextFieldStyle = concatStyleSets(textFieldStyle, {
117
20
  fieldGroup: styles === null || styles === void 0 ? void 0 : styles.textField,
@@ -124,511 +27,56 @@ export const InputBoxComponent = (props) => {
124
27
  }
125
28
  });
126
29
  const mergedChildrenStyle = mergeStyles(props.inlineChildren ? {} : newLineButtonsContainerStyle);
127
- /* @conditional-compile-remove(mention) */
128
- const onSuggestionSelected = useCallback((suggestion) => {
129
- var _a, _b, _c;
130
- let selectionEnd = ((_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.selectionEnd) || -1;
131
- if (selectionEnd < 0) {
132
- selectionEnd = 0;
133
- }
134
- else if (selectionEnd > inputTextValue.length) {
135
- selectionEnd = inputTextValue.length;
136
- }
137
- const oldPlainText = inputTextValue;
138
- const mention = htmlStringForMentionSuggestion(suggestion, localeStrings);
139
- // update plain text with the mention html text
140
- const newPlainText = inputTextValue.substring(0, currentTriggerStartIndex) + mention + inputTextValue.substring(selectionEnd);
141
- const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : DEFAULT_MENTION_TRIGGER;
142
- // update html text with updated plain text
143
- const updatedContent = updateHTML({
144
- htmlText: textValue,
145
- oldPlainText,
146
- newPlainText,
147
- tags: tagsValue,
148
- startIndex: currentTriggerStartIndex,
149
- oldPlainTextEndIndex: selectionEnd,
150
- change: mention,
151
- mentionTrigger: triggerText
152
- });
153
- const displayName = getDisplayNameForMentionSuggestion(suggestion, localeStrings);
154
- const newCaretIndex = currentTriggerStartIndex + displayName.length + triggerText.length;
155
- // move the caret in the text field to the end of the mention plain text
156
- setCaretIndex(newCaretIndex);
157
- setSelectionEndValue(newCaretIndex);
158
- setSelectionStartValue(newCaretIndex);
159
- setCurrentTriggerStartIndex(-1);
160
- updateMentionSuggestions([]);
161
- // set focus back to text field
162
- (_c = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _c === void 0 ? void 0 : _c.focus();
163
- setActiveSuggestionIndex(undefined);
164
- onChange && onChange(undefined, updatedContent.updatedHTML);
165
- }, [
166
- textFieldRef,
167
- inputTextValue,
168
- currentTriggerStartIndex,
169
- mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger,
170
- onChange,
171
- textValue,
172
- tagsValue,
173
- /* @conditional-compile-remove(mention) */
174
- updateMentionSuggestions,
175
- /* @conditional-compile-remove(mention) */
176
- localeStrings
177
- ]);
178
30
  const onTextFieldKeyDown = useCallback((ev) => {
179
- /* @conditional-compile-remove(mention) */
180
- // caretIndex should be set to undefined when the user is typing
181
- setCaretIndex(undefined);
182
- // shouldHandleOnMouseDownDuringSelect should be set to false after the last mouse down event.
183
- // it shouldn't be updated in onMouseUp
184
- // as onMouseUp can be triggered before or after onSelect event
185
- // because its order depends on mouse events not selection.
186
- /* @conditional-compile-remove(mention) */
187
- setShouldHandleOnMouseDownDuringSelect(false);
188
31
  if (isEnterKeyEventFromCompositionSession(ev)) {
189
32
  return;
190
33
  }
191
- /* @conditional-compile-remove(mention) */
192
- if (mentionSuggestions.length > 0) {
193
- if (ev.key === 'ArrowUp') {
194
- ev.preventDefault();
195
- const newActiveIndex = activeSuggestionIndex === undefined
196
- ? mentionSuggestions.length - 1
197
- : Math.max(activeSuggestionIndex - 1, 0);
198
- setActiveSuggestionIndex(newActiveIndex);
199
- }
200
- else if (ev.key === 'ArrowDown') {
201
- ev.preventDefault();
202
- const newActiveIndex = activeSuggestionIndex === undefined
203
- ? 0
204
- : Math.min(activeSuggestionIndex + 1, mentionSuggestions.length - 1);
205
- setActiveSuggestionIndex(newActiveIndex);
206
- }
207
- else if (ev.key === 'Escape') {
208
- updateMentionSuggestions([]);
209
- }
210
- }
211
34
  if (ev.key === 'Enter' && (ev.shiftKey === false || !supportNewline)) {
212
35
  ev.preventDefault();
213
- // If we are looking up a mention, select the focused suggestion
214
- /* @conditional-compile-remove(mention) */
215
- if (mentionSuggestions.length > 0 && activeSuggestionIndex !== undefined) {
216
- const selectedMention = mentionSuggestions[activeSuggestionIndex];
217
- if (selectedMention) {
218
- onSuggestionSelected(selectedMention);
219
- return;
220
- }
221
- }
222
36
  onEnterKeyDown && onEnterKeyDown();
223
37
  }
224
38
  onKeyDown && onKeyDown(ev);
225
- }, [
226
- onEnterKeyDown,
227
- onKeyDown,
228
- supportNewline,
229
- /* @conditional-compile-remove(mention) */
230
- mentionSuggestions,
231
- /* @conditional-compile-remove(mention) */
232
- activeSuggestionIndex,
233
- /* @conditional-compile-remove(mention) */
234
- onSuggestionSelected,
235
- /* @conditional-compile-remove(mention) */
236
- updateMentionSuggestions
237
- ]);
39
+ }, [onEnterKeyDown, onKeyDown, supportNewline]);
238
40
  const onRenderChildren = () => {
239
41
  return (React.createElement(Stack, { horizontal: true, className: mergedChildrenStyle }, children));
240
42
  };
241
- /* @conditional-compile-remove(mention) */
242
- const debouncedQueryUpdate = useDebouncedCallback((query) => __awaiter(void 0, void 0, void 0, function* () {
243
- var _a;
244
- const suggestions = (_a = (yield (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.onQueryUpdated(query)))) !== null && _a !== void 0 ? _a : [];
245
- if (suggestions.length === 0) {
246
- setActiveSuggestionIndex(undefined);
247
- }
248
- else if (activeSuggestionIndex === undefined) {
249
- // Set the active to the first, if it's not already set
250
- setActiveSuggestionIndex(0);
251
- }
252
- updateMentionSuggestions(suggestions);
253
- }), 500);
254
- /* @conditional-compile-remove(mention) */
255
- // Update selections index in mention to navigate by words
256
- const updateSelectionIndexesWithMentionIfNeeded = useCallback(({ event, inputTextValue, selectionEndValue, selectionStartValue, tagsValue }) => {
257
- var _a, _b, _c;
258
- let updatedStartIndex = event.currentTarget.selectionStart;
259
- let updatedEndIndex = event.currentTarget.selectionEnd;
260
- if (event.currentTarget.selectionStart === event.currentTarget.selectionEnd &&
261
- event.currentTarget.selectionStart !== null &&
262
- event.currentTarget.selectionStart !== -1) {
263
- // just a caret movement/usual typing or deleting
264
- const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
265
- // don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
266
- if (mentionTag !== undefined &&
267
- mentionTag.plainTextBeginIndex !== undefined &&
268
- event.currentTarget.selectionStart > mentionTag.plainTextBeginIndex &&
269
- event.currentTarget.selectionStart < ((_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex)) {
270
- // get updated selection index
271
- const newSelectionIndex = findNewSelectionIndexForMention({
272
- tag: mentionTag,
273
- textValue: inputTextValue,
274
- currentSelectionIndex: event.currentTarget.selectionStart,
275
- previousSelectionIndex: selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : inputTextValue.length
276
- });
277
- updatedStartIndex = newSelectionIndex;
278
- updatedEndIndex = newSelectionIndex;
279
- }
280
- }
281
- else if (event.currentTarget.selectionStart !== event.currentTarget.selectionEnd) {
282
- // Both e.currentTarget.selectionStart !== selectionStartValue and e.currentTarget.selectionEnd !== selectionEndValue can be true when a user selects a text by double click
283
- if (event.currentTarget.selectionStart !== null && event.currentTarget.selectionStart !== selectionStartValue) {
284
- // the selection start is changed
285
- const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
286
- // don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
287
- if (mentionTag !== undefined &&
288
- mentionTag.plainTextBeginIndex !== undefined &&
289
- event.currentTarget.selectionStart > mentionTag.plainTextBeginIndex &&
290
- event.currentTarget.selectionStart < ((_b = mentionTag.plainTextEndIndex) !== null && _b !== void 0 ? _b : mentionTag.plainTextBeginIndex)) {
291
- updatedStartIndex = findNewSelectionIndexForMention({
292
- tag: mentionTag,
293
- textValue: inputTextValue,
294
- currentSelectionIndex: event.currentTarget.selectionStart,
295
- previousSelectionIndex: selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : inputTextValue.length
296
- });
297
- }
298
- }
299
- if (event.currentTarget.selectionEnd !== null && event.currentTarget.selectionEnd !== selectionEndValue) {
300
- // the selection end is changed
301
- const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionEnd);
302
- // don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
303
- if (mentionTag !== undefined &&
304
- mentionTag.plainTextBeginIndex !== undefined &&
305
- event.currentTarget.selectionEnd > mentionTag.plainTextBeginIndex &&
306
- event.currentTarget.selectionEnd < ((_c = mentionTag.plainTextEndIndex) !== null && _c !== void 0 ? _c : mentionTag.plainTextBeginIndex)) {
307
- updatedEndIndex = findNewSelectionIndexForMention({
308
- tag: mentionTag,
309
- textValue: inputTextValue,
310
- currentSelectionIndex: event.currentTarget.selectionEnd,
311
- previousSelectionIndex: selectionEndValue !== null && selectionEndValue !== void 0 ? selectionEndValue : inputTextValue.length
312
- });
313
- }
314
- }
315
- }
316
- // e.currentTarget.selectionDirection should be set to handle shift + arrow keys
317
- if (event.currentTarget.selectionDirection === null) {
318
- event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex);
319
- }
320
- else {
321
- event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex, event.currentTarget.selectionDirection);
322
- }
323
- setSelectionStartValue(nullToUndefined(updatedStartIndex));
324
- setSelectionEndValue(nullToUndefined(updatedEndIndex));
325
- }, [setSelectionStartValue, setSelectionEndValue]);
326
- /* @conditional-compile-remove(mention) */
327
- const handleOnSelect = useCallback(({ event, inputTextValue, tags, shouldHandleOnMouseDownDuringSelect, selectionStartValue, selectionEndValue }) => {
328
- if (shouldHandleOnMouseDownDuringSelect) {
329
- if (targetSelection !== undefined) {
330
- setSelectionStartValue(targetSelection.start);
331
- setSelectionEndValue(targetSelection.end);
332
- event.currentTarget.setSelectionRange(targetSelection.start, undefinedToNull(targetSelection.end));
333
- setTargetSelection(undefined);
334
- }
335
- else if (event.currentTarget.selectionStart !== null) {
336
- // on select was triggered by mouse down/up with no movement
337
- const mentionTag = findMentionTagForSelection(tags, event.currentTarget.selectionStart);
338
- if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
339
- // handle mention click
340
- // Get range of word that was clicked on
341
- const selectionRange = rangeOfWordInSelection({
342
- textInput: inputTextValue,
343
- selectionStart: event.currentTarget.selectionStart,
344
- selectionEnd: nullToUndefined(event.currentTarget.selectionEnd),
345
- tag: mentionTag
346
- });
347
- if (event.currentTarget.selectionDirection === null) {
348
- event.currentTarget.setSelectionRange(selectionRange.start, selectionRange.end);
349
- }
350
- else {
351
- event.currentTarget.setSelectionRange(selectionRange.start, selectionRange.end, event.currentTarget.selectionDirection);
352
- }
353
- setSelectionStartValue(selectionRange.start);
354
- setSelectionEndValue(selectionRange.end);
355
- }
356
- else {
357
- setSelectionStartValue(event.currentTarget.selectionStart);
358
- setSelectionEndValue(nullToUndefined(event.currentTarget.selectionEnd));
359
- }
360
- }
361
- }
362
- else {
363
- // selection was changed by keyboard
364
- updateSelectionIndexesWithMentionIfNeeded({
365
- event,
366
- inputTextValue,
367
- selectionStartValue,
368
- selectionEndValue,
369
- tagsValue: tags
370
- });
371
- }
372
- // don't set setShouldHandleOnMouseDownDuringSelect(false) here as setSelectionRange
373
- // could trigger additional calls of onSelect event and they may not be handled correctly
374
- // (because of setSelectionRange calls or rerender)
375
- }, [
376
- updateSelectionIndexesWithMentionIfNeeded,
377
- targetSelection,
378
- setTargetSelection,
379
- setSelectionStartValue,
380
- setSelectionEndValue
381
- ]);
382
- /* @conditional-compile-remove(mention) */
383
- const handleOnChange = useCallback(({ currentSelectionEnd, currentSelectionStart, currentTriggerStartIndex, event, htmlTextValue, inputTextValue, previousSelectionEnd, previousSelectionStart, tagsValue, updatedValue }) => __awaiter(void 0, void 0, void 0, function* () {
384
- var _b;
385
- debouncedQueryUpdate.cancel();
386
- if (event.currentTarget === null) {
387
- return;
388
- }
389
- // handle backspace change
390
- // onSelect is not called for backspace as selection is not changed and local caret index is outdated
391
- setCaretIndex(undefined);
392
- const newValue = updatedValue !== null && updatedValue !== void 0 ? updatedValue : '';
393
- const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : DEFAULT_MENTION_TRIGGER;
394
- const newTextLength = newValue.length;
395
- // updating indexes to set between 0 and text length, otherwise selectionRange won't be set correctly
396
- const currentSelectionEndValue = getValidatedIndexInRange({
397
- min: 0,
398
- max: newTextLength,
399
- currentValue: currentSelectionEnd
400
- });
401
- const currentSelectionStartValue = getValidatedIndexInRange({
402
- min: 0,
403
- max: newTextLength,
404
- currentValue: currentSelectionStart
405
- });
406
- const previousSelectionStartValue = getValidatedIndexInRange({
407
- min: 0,
408
- max: inputTextValue.length,
409
- currentValue: previousSelectionStart
410
- });
411
- const previousSelectionEndValue = getValidatedIndexInRange({
412
- min: 0,
413
- max: inputTextValue.length,
414
- currentValue: previousSelectionEnd
415
- });
416
- // If we are enabled for lookups,
417
- if (mentionLookupOptions !== undefined) {
418
- // Look at the range of the change for a trigger character
419
- const triggerPriorIndex = newValue.lastIndexOf(triggerText, currentSelectionEndValue - 1);
420
- // Update the caret position, if not doing a lookup
421
- setCaretPosition(Caret.getRelativePosition(event.currentTarget));
422
- if (triggerPriorIndex !== undefined) {
423
- // trigger is found
424
- const isSpaceBeforeTrigger = newValue.substring(triggerPriorIndex - 1, triggerPriorIndex) === ' ';
425
- const wordAtSelection = newValue.substring(triggerPriorIndex, currentSelectionEndValue);
426
- let tagIndex = currentTriggerStartIndex;
427
- if (!isSpaceBeforeTrigger && triggerPriorIndex !== 0) {
428
- //no space before the trigger <- continuation of the previous word
429
- tagIndex = -1;
430
- setCurrentTriggerStartIndex(tagIndex);
431
- }
432
- else if (wordAtSelection === triggerText) {
433
- // start of the mention
434
- tagIndex = currentSelectionEndValue - triggerText.length;
435
- if (tagIndex < 0) {
436
- tagIndex = 0;
437
- }
438
- setCurrentTriggerStartIndex(tagIndex);
439
- }
440
- if (tagIndex === -1) {
441
- updateMentionSuggestions([]);
442
- }
443
- else {
444
- // In the middle of a @mention lookup
445
- if (tagIndex > -1) {
446
- const query = wordAtSelection.substring(triggerText.length, wordAtSelection.length);
447
- if (query !== undefined) {
448
- yield debouncedQueryUpdate(query);
449
- }
450
- }
451
- }
452
- }
453
- }
454
- let result = '';
455
- if (tagsValue.length === 0) {
456
- // no tags in the string and newValue should be used as a result string
457
- result = newValue;
458
- }
459
- else {
460
- // there are tags in the text value and htmlTextValue is html string
461
- // find diff between old and new text
462
- const { changeStart, oldChangeEnd, newChangeEnd } = findStringsDiffIndexes({
463
- oldText: inputTextValue,
464
- newText: newValue,
465
- previousSelectionStart: previousSelectionStartValue,
466
- previousSelectionEnd: previousSelectionEndValue,
467
- currentSelectionStart: currentSelectionStartValue,
468
- currentSelectionEnd: currentSelectionEndValue
469
- });
470
- const change = newValue.substring(changeStart, newChangeEnd);
471
- // get updated html string
472
- const updatedContent = updateHTML({
473
- htmlText: htmlTextValue,
474
- oldPlainText: inputTextValue,
475
- newPlainText: newValue,
476
- tags: tagsValue,
477
- startIndex: changeStart,
478
- oldPlainTextEndIndex: oldChangeEnd,
479
- change,
480
- mentionTrigger: triggerText
481
- });
482
- result = updatedContent.updatedHTML;
483
- // update caret index if needed
484
- if (updatedContent.updatedSelectionIndex !== undefined) {
485
- setCaretIndex(updatedContent.updatedSelectionIndex);
486
- setSelectionEndValue(updatedContent.updatedSelectionIndex);
487
- setSelectionStartValue(updatedContent.updatedSelectionIndex);
488
- }
489
- }
490
- onChange && onChange(event, result);
491
- }), [onChange, mentionLookupOptions, setCaretIndex, setCaretPosition, updateMentionSuggestions, debouncedQueryUpdate]);
492
- const getInputFieldTextValue = () => {
43
+ const renderTextField = () => {
44
+ const textFieldProps = {
45
+ autoFocus: props.autoFocus === 'sendBoxTextField',
46
+ multiline: true,
47
+ autoAdjustHeight: true,
48
+ multiple: false,
49
+ resizable: false,
50
+ componentRef: textFieldRef,
51
+ id,
52
+ inputClassName: mergedInputFieldStyle,
53
+ placeholder: placeholderText,
54
+ autoComplete: 'off',
55
+ styles: mergedTextFieldStyle,
56
+ disabled,
57
+ errorMessage,
58
+ onRenderSuffix: onRenderChildren
59
+ };
493
60
  /* @conditional-compile-remove(mention) */
494
- return inputTextValue;
495
- return textValue;
496
- };
497
- /* @conditional-compile-remove(mention) */
498
- // Adjust the selection range based on a mouse / touch interaction
499
- const handleOnMove = useCallback((event) => {
500
- var _a;
501
- let targetStart = event.currentTarget.selectionStart;
502
- let targetEnd = event.currentTarget.selectionEnd;
503
- // Should we do anything?
504
- if (interactionStartPoint !== undefined &&
505
- // And did selection change?
506
- targetStart !== null &&
507
- (targetStart !== (targetSelection === null || targetSelection === void 0 ? void 0 : targetSelection.start) || targetEnd !== (targetSelection === null || targetSelection === void 0 ? void 0 : targetSelection.end))) {
508
- const direction = event.clientX > interactionStartPoint.x ? 'forward' : 'backward';
509
- const mentionTag = findMentionTagForSelection(tagsValue, direction === 'backward'
510
- ? event.currentTarget.selectionStart
511
- : (_a = event.currentTarget.selectionEnd) !== null && _a !== void 0 ? _a : event.currentTarget.selectionStart);
512
- let updateCurrentTarget = false;
513
- if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
514
- targetStart = Math.min(mentionTag.plainTextBeginIndex, targetStart);
515
- if (mentionTag.plainTextEndIndex !== undefined && targetEnd !== null) {
516
- targetEnd = Math.max(mentionTag.plainTextEndIndex, targetEnd);
517
- }
518
- updateCurrentTarget = true;
519
- setShouldHandleOnMouseDownDuringSelect(false);
520
- }
521
- // Update selection range
522
- setTargetSelection({ start: targetStart, end: targetEnd });
523
- if (updateCurrentTarget) {
524
- // Only set the control, if the values are updated
525
- event.currentTarget.setSelectionRange(targetStart, targetEnd, direction);
526
- }
527
- }
528
- }, [setTargetSelection, targetSelection, setShouldHandleOnMouseDownDuringSelect, interactionStartPoint, tagsValue]);
529
- /* @conditional-compile-remove(mention) */
530
- const announcerText = useMemo(() => {
531
- if (activeSuggestionIndex === undefined) {
532
- return undefined;
61
+ const textFieldWithMentionProps = {
62
+ textFieldProps: textFieldProps,
63
+ dataUiId: dataUiId,
64
+ textValue: textValue,
65
+ onChange: onChange,
66
+ onKeyDown: onKeyDown,
67
+ onEnterKeyDown: onEnterKeyDown,
68
+ textFieldRef: textFieldRef,
69
+ supportNewline: supportNewline,
70
+ mentionLookupOptions: props.mentionLookupOptions
71
+ };
72
+ /* @conditional-compile-remove(mention) */
73
+ if (props.mentionLookupOptions) {
74
+ return React.createElement(TextFieldWithMention, Object.assign({}, textFieldWithMentionProps));
533
75
  }
534
- const currentMention = mentionSuggestions[activeSuggestionIndex !== null && activeSuggestionIndex !== void 0 ? activeSuggestionIndex : 0];
535
- return (currentMention === null || currentMention === void 0 ? void 0 : currentMention.displayText.length) > 0
536
- ? currentMention === null || currentMention === void 0 ? void 0 : currentMention.displayText
537
- : localeStrings.participantItem.displayNamePlaceholder;
538
- }, [activeSuggestionIndex, mentionSuggestions, localeStrings.participantItem.displayNamePlaceholder]);
76
+ return (React.createElement(TextField, Object.assign({}, textFieldProps, { "data-ui-id": dataUiId, value: textValue, onChange: onChange, onKeyDown: onTextFieldKeyDown })));
77
+ };
539
78
  return (React.createElement(Stack, { className: mergedRootStyle },
540
- React.createElement("div", { className: mergedTextContainerStyle },
541
- /* @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: () => {
542
- updateMentionSuggestions([]);
543
- } })),
544
- /* @conditional-compile-remove(mention) */ announcerText !== undefined && (React.createElement(Announcer, { announcementString: announcerText, ariaLive: 'polite' })),
545
- React.createElement(TextField, { autoFocus: props.autoFocus === 'sendBoxTextField', "data-ui-id": dataUiId, multiline: true, autoAdjustHeight: true, multiple: false, resizable: false, componentRef: textFieldRef, id: id, inputClassName: mergedInputFieldStyle, placeholder: placeholderText, value: getInputFieldTextValue(), onChange: (e, newValue) => {
546
- // Remove when switching to react 17+, currently needed because of https://legacy.reactjs.org/docs/legacy-event-pooling.html
547
- /* @conditional-compile-remove(mention) */
548
- // Prevents React from resetting event's properties
549
- e.persist();
550
- /* @conditional-compile-remove(mention) */
551
- setInputTextValue(newValue !== null && newValue !== void 0 ? newValue : '');
552
- /* @conditional-compile-remove(mention) */
553
- handleOnChange({
554
- event: e,
555
- tagsValue,
556
- htmlTextValue: textValue,
557
- inputTextValue,
558
- currentTriggerStartIndex,
559
- previousSelectionStart: nullToUndefined(selectionStartValue),
560
- previousSelectionEnd: nullToUndefined(selectionEndValue),
561
- currentSelectionStart: nullToUndefined(e.currentTarget.selectionStart),
562
- currentSelectionEnd: nullToUndefined(e.currentTarget.selectionEnd),
563
- updatedValue: newValue
564
- });
565
- /* @conditional-compile-remove(mention) */
566
- return;
567
- onChange(e, newValue);
568
- },
569
- /* @conditional-compile-remove(mention) */
570
- onSelect: (e) => {
571
- // update selection if needed
572
- if (caretIndex !== undefined) {
573
- setCaretIndex(undefined);
574
- // sometimes setting selectionRage in effect for updating caretIndex doesn't work as expected and onSelect should handle this case
575
- if (caretIndex !== e.currentTarget.selectionStart || caretIndex !== e.currentTarget.selectionEnd) {
576
- e.currentTarget.setSelectionRange(caretIndex, caretIndex);
577
- }
578
- return;
579
- }
580
- handleOnSelect({
581
- event: e,
582
- inputTextValue,
583
- shouldHandleOnMouseDownDuringSelect,
584
- selectionEndValue,
585
- selectionStartValue,
586
- tags: tagsValue
587
- });
588
- },
589
- /* @conditional-compile-remove(mention) */
590
- onMouseDown: (e) => {
591
- setInteractionStartPoint({ x: e.clientX, y: e.clientY });
592
- // as events order is onMouseDown -> onMouseMove -> onMouseUp -> onSelect -> onClick
593
- // onClick and onMouseDown can't handle clicking on mention event because
594
- // onMouseDown doesn't have correct selectionRange yet and
595
- // onClick already has wrong range as it's called after onSelect that updates the selection range
596
- // so we need to handle onMouseDown to prevent onSelect default behavior
597
- setShouldHandleOnMouseDownDuringSelect(true);
598
- },
599
- /* @conditional-compile-remove(mention) */
600
- onMouseMove: handleOnMove,
601
- /* @conditional-compile-remove(mention) */
602
- onMouseUp: () => {
603
- setInteractionStartPoint(undefined);
604
- },
605
- /* @conditional-compile-remove(mention) */
606
- onTouchStart: (e) => {
607
- setInteractionStartPoint({
608
- x: e.targetTouches.item(0).clientX,
609
- y: e.targetTouches.item(0).clientY
610
- });
611
- // see onMouseDown for more details
612
- setShouldHandleOnMouseDownDuringSelect(true);
613
- },
614
- /* @conditional-compile-remove(mention) */
615
- onTouchMove: handleOnMove,
616
- /* @conditional-compile-remove(mention) */
617
- onTouchEnd: () => {
618
- setInteractionStartPoint(undefined);
619
- },
620
- /* @conditional-compile-remove(mention) */
621
- onBlur: () => {
622
- // setup all flags to default values when text field loses focus
623
- setShouldHandleOnMouseDownDuringSelect(false);
624
- setCaretIndex(undefined);
625
- setSelectionStartValue(undefined);
626
- setSelectionEndValue(undefined);
627
- // Dismiss the suggestions on blur, after enough time to select by mouse if needed
628
- setTimeout(() => {
629
- setMentionSuggestions([]);
630
- }, 200);
631
- }, autoComplete: "off", onKeyDown: onTextFieldKeyDown, styles: mergedTextFieldStyle, disabled: disabled, errorMessage: errorMessage, onRenderSuffix: onRenderChildren, elementRef: inputBoxRef }))));
79
+ React.createElement("div", { className: mergedTextContainerStyle }, renderTextField())));
632
80
  };
633
81
  /**
634
82
  * @private
@@ -654,789 +102,4 @@ export const InputBoxButton = (props) => {
654
102
  // VoiceOver fix: Avoid icon from stealing focus when IconButton is double-tapped to send message by wrapping with Stack with pointerEvents style to none
655
103
  onRenderIcon: () => React.createElement(Stack, { className: iconWrapperStyle }, onRenderIcon(isHover)) })));
656
104
  };
657
- /* @conditional-compile-remove(mention) */
658
- /**
659
- * Get validated value for index between min and max values. If currentValue is not defined, -1 will be used instead.
660
- *
661
- * @private
662
- * @param props - Props for finding a valid index in range.
663
- * @returns Valid index in the range.
664
- */
665
- const getValidatedIndexInRange = (props) => {
666
- const { min, max, currentValue } = props;
667
- let updatedValue = currentValue !== null && currentValue !== void 0 ? currentValue : -1;
668
- updatedValue = Math.max(min, updatedValue);
669
- updatedValue = Math.min(updatedValue, max);
670
- return updatedValue;
671
- };
672
- /* @conditional-compile-remove(mention) */
673
- /**
674
- * Find mention tag for selection if exists.
675
- *
676
- * @private
677
- * @param tags - Existing list of tags.
678
- * @param selection - Selection index.
679
- * @returns Mention tag if exists, otherwise undefined.
680
- */
681
- const findMentionTagForSelection = (tags, selection) => {
682
- let mentionTag = undefined;
683
- tags.every((tag) => {
684
- const closingTagInfo = getTagClosingTagInfo(tag);
685
- if (tag.plainTextBeginIndex !== undefined && tag.plainTextBeginIndex > selection) {
686
- // no need to check further as the selection is before the tag
687
- return false;
688
- }
689
- else if (tag.plainTextBeginIndex !== undefined &&
690
- tag.plainTextBeginIndex <= selection &&
691
- selection <= closingTagInfo.plainTextEndIndex) {
692
- // no need to check if tag doesn't contain selection
693
- if (tag.subTags !== undefined && tag.subTags.length !== 0) {
694
- const selectedTag = findMentionTagForSelection(tag.subTags, selection);
695
- if (selectedTag !== undefined) {
696
- mentionTag = selectedTag;
697
- return false;
698
- }
699
- }
700
- else if (tag.tagType === MSFT_MENTION_TAG) {
701
- mentionTag = tag;
702
- return false;
703
- }
704
- }
705
- return true;
706
- });
707
- return mentionTag;
708
- };
709
- /* @conditional-compile-remove(mention) */
710
- const rangeOfWordInSelection = ({ textInput, selectionStart, selectionEnd, tag }) => {
711
- var _a;
712
- if (tag.plainTextBeginIndex === undefined) {
713
- return { start: selectionStart, end: selectionEnd === undefined ? selectionStart : selectionEnd };
714
- }
715
- // Look at start word index and optionally end word index.
716
- // Select combination of the two and return the range.
717
- let start = selectionStart;
718
- let end = selectionEnd === undefined ? selectionStart : selectionEnd;
719
- const firstWordStartIndex = textInput.lastIndexOf(' ', selectionStart);
720
- if (firstWordStartIndex === tag.plainTextBeginIndex) {
721
- start = firstWordStartIndex;
722
- }
723
- else {
724
- start = Math.max(firstWordStartIndex + 1, tag.plainTextBeginIndex);
725
- }
726
- const firstWordEndIndex = textInput.indexOf(' ', selectionStart);
727
- end = Math.max(firstWordEndIndex + 1, (_a = tag.plainTextEndIndex) !== null && _a !== void 0 ? _a : firstWordEndIndex + 1);
728
- if (selectionEnd !== undefined && tag.plainTextEndIndex !== undefined) {
729
- const lastWordEndIndex = textInput.indexOf(' ', selectionEnd);
730
- end = Math.max(lastWordEndIndex > -1 ? lastWordEndIndex : tag.plainTextEndIndex, selectionEnd);
731
- }
732
- return { start, end };
733
- };
734
- /* @conditional-compile-remove(mention) */
735
- /**
736
- * Find a new the selection index.
737
- *
738
- * @private
739
- * @param props - Props for finding new selection index for mention.
740
- * @returns New selection index if it is inside of a mention tag, otherwise the current selection.
741
- */
742
- const findNewSelectionIndexForMention = (props) => {
743
- var _a;
744
- const { tag, textValue, currentSelectionIndex, previousSelectionIndex } = props;
745
- // check if this is a mention tag and selection should be updated
746
- if (tag.tagType !== MSFT_MENTION_TAG ||
747
- tag.plainTextBeginIndex === undefined ||
748
- currentSelectionIndex === previousSelectionIndex ||
749
- tag.plainTextEndIndex === undefined) {
750
- return currentSelectionIndex;
751
- }
752
- let spaceIndex = 0;
753
- if (currentSelectionIndex <= previousSelectionIndex) {
754
- // the cursor is moved to the left, find the last index before the cursor
755
- spaceIndex = textValue.lastIndexOf(' ', currentSelectionIndex !== null && currentSelectionIndex !== void 0 ? currentSelectionIndex : 0);
756
- if (spaceIndex === -1) {
757
- // no space before the selection, use the beginning of the tag
758
- spaceIndex = tag.plainTextBeginIndex;
759
- }
760
- }
761
- else {
762
- // the cursor is moved to the right, find the fist index after the cursor
763
- spaceIndex = textValue.indexOf(' ', currentSelectionIndex !== null && currentSelectionIndex !== void 0 ? currentSelectionIndex : 0);
764
- if (spaceIndex === -1) {
765
- // no space after the selection, use the end of the tag
766
- spaceIndex = (_a = tag.plainTextEndIndex) !== null && _a !== void 0 ? _a : tag.plainTextBeginIndex;
767
- }
768
- }
769
- spaceIndex = Math.max(tag.plainTextBeginIndex, spaceIndex);
770
- spaceIndex = Math.min(tag.plainTextEndIndex, spaceIndex);
771
- return spaceIndex;
772
- };
773
- /* @conditional-compile-remove(mention) */
774
- /**
775
- * Handle mention tag edit and by word deleting
776
- *
777
- * @private
778
- * @param props - Props for mention update HTML function.
779
- * @returns Updated texts and indexes.
780
- */
781
- const handleMentionTagUpdate = (props) => {
782
- const { htmlText, oldPlainText, change, tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength } = props;
783
- let processedChange = props.processedChange;
784
- let lastProcessedHTMLIndex = props.lastProcessedHTMLIndex;
785
- if (tag.tagType !== MSFT_MENTION_TAG || tag.plainTextBeginIndex === undefined) {
786
- // not a mention tag
787
- return {
788
- result: '',
789
- updatedChange: processedChange,
790
- htmlIndex: lastProcessedHTMLIndex,
791
- plainTextSelectionEndIndex: undefined
792
- };
793
- }
794
- let result = '';
795
- let plainTextSelectionEndIndex;
796
- let rangeStart;
797
- let rangeEnd;
798
- // check if space symbol is handled in case if string looks like '<1 2 3>'
799
- let isSpaceLengthHandled = false;
800
- rangeStart = oldPlainText.lastIndexOf(' ', startIndex);
801
- if (rangeStart !== -1 && rangeStart !== undefined && rangeStart > tag.plainTextBeginIndex) {
802
- isSpaceLengthHandled = true;
803
- }
804
- rangeEnd = oldPlainText.indexOf(' ', oldPlainTextEndIndex);
805
- if (rangeEnd === -1 || rangeEnd === undefined) {
806
- // check if space symbol is not found
807
- rangeEnd = plainTextEndIndex;
808
- }
809
- else if (!isSpaceLengthHandled) {
810
- // +1 to include the space symbol
811
- rangeEnd += 1;
812
- }
813
- isSpaceLengthHandled = true;
814
- if (rangeStart === -1 || rangeStart === undefined || rangeStart < tag.plainTextBeginIndex) {
815
- // rangeStart should be at least equal to tag.plainTextBeginIndex
816
- rangeStart = tag.plainTextBeginIndex;
817
- }
818
- if (rangeEnd > plainTextEndIndex) {
819
- // rangeEnd should be at most equal to plainTextEndIndex
820
- rangeEnd = plainTextEndIndex;
821
- }
822
- if (rangeStart === tag.plainTextBeginIndex && rangeEnd === plainTextEndIndex) {
823
- // the whole tag should be removed
824
- result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
825
- plainTextSelectionEndIndex = tag.plainTextBeginIndex + processedChange.length;
826
- processedChange = '';
827
- lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
828
- }
829
- else {
830
- // only part of the tag should be removed
831
- let startChangeDiff = 0;
832
- let endChangeDiff = 0;
833
- // need to check only rangeStart > tag.plainTextBeginIndex as when rangeStart === tag.plainTextBeginIndex startChangeDiff = 0 and mentionTagLength shouldn't be subtracted
834
- if (rangeStart > tag.plainTextBeginIndex) {
835
- startChangeDiff = rangeStart - tag.plainTextBeginIndex - mentionTagLength;
836
- }
837
- endChangeDiff = rangeEnd - tag.plainTextBeginIndex - mentionTagLength;
838
- result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff);
839
- if (startIndex < tag.plainTextBeginIndex) {
840
- // if the change is before the tag, the selection should start from startIndex (rangeStart will be equal to tag.plainTextBeginIndex)
841
- plainTextSelectionEndIndex = startIndex + change.length;
842
- }
843
- else {
844
- // if the change is inside the tag, the selection should start with rangeStart
845
- plainTextSelectionEndIndex = rangeStart + processedChange.length;
846
- }
847
- lastProcessedHTMLIndex = tag.openTagIndex + tag.openTagBody.length + endChangeDiff;
848
- // processed change should not be changed as it should be added after the tag
849
- }
850
- return { result, updatedChange: processedChange, htmlIndex: lastProcessedHTMLIndex, plainTextSelectionEndIndex };
851
- };
852
- /* @conditional-compile-remove(mention) */
853
- /**
854
- * Get closing tag information if exists otherwise return information as for self closing tag
855
- *
856
- * @private
857
- * @param tag - Tag data.
858
- * @returns Closing tag information for the provided tag.
859
- */
860
- const getTagClosingTagInfo = (tag) => {
861
- let plainTextEndIndex = 0;
862
- let closeTagIdx = 0;
863
- let closeTagLength = 0;
864
- if (tag.plainTextEndIndex !== undefined && tag.closingTagIndex !== undefined) {
865
- // close tag exists
866
- plainTextEndIndex = tag.plainTextEndIndex;
867
- closeTagIdx = tag.closingTagIndex;
868
- // tag.tagType.length + </>
869
- closeTagLength = tag.tagType.length + 3;
870
- }
871
- else if (tag.plainTextBeginIndex !== undefined) {
872
- // no close tag
873
- plainTextEndIndex = tag.plainTextBeginIndex;
874
- closeTagIdx = tag.openTagIndex + tag.openTagBody.length;
875
- closeTagLength = 0;
876
- }
877
- return { plainTextEndIndex, closeTagIdx, closeTagLength };
878
- };
879
- /* @conditional-compile-remove(mention) */
880
- /**
881
- * Go through the text and update it with the changed text
882
- *
883
- * @private
884
- * @param props - Props for update HTML function.
885
- * @returns Updated HTML and selection index if the selection index should be set.
886
- */
887
- const updateHTML = (props) => {
888
- const { htmlText, oldPlainText, newPlainText, tags, startIndex, oldPlainTextEndIndex, change, mentionTrigger } = props;
889
- if (tags.length === 0 || (startIndex === 0 && oldPlainTextEndIndex === oldPlainText.length - 1)) {
890
- // no tags added yet or the whole text is changed
891
- return { updatedHTML: newPlainText, updatedSelectionIndex: undefined };
892
- }
893
- let result = '';
894
- let lastProcessedHTMLIndex = 0;
895
- // the value can be updated with empty string when the change covers more than 1 place (tag + before or after the tag)
896
- // in this case change won't be added as part of the tag
897
- // 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
898
- // 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
899
- // e.g.: change is on the beginning of the tag => change will be added before the tag
900
- // 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
901
- let processedChange = change;
902
- // end tag plain text index of the last processed tag
903
- let lastProcessedPlainTextTagEndIndex = 0;
904
- // as some tags/text can be removed fully, selection should be updated correctly
905
- let changeNewEndIndex;
906
- for (let i = 0; i < tags.length; i++) {
907
- const tag = tags[i];
908
- if (tag.plainTextBeginIndex === undefined) {
909
- continue;
910
- }
911
- // all plain text indexes includes trigger length for the mention that shouldn't be included in
912
- // htmlText.substring because html strings don't include the trigger
913
- // mentionTagLength will be set only for mention tag, otherwise should be 0
914
- let mentionTagLength = 0;
915
- let isMentionTag = false;
916
- if (tag.tagType === MSFT_MENTION_TAG) {
917
- mentionTagLength = mentionTrigger.length;
918
- isMentionTag = true;
919
- }
920
- if (startIndex <= tag.plainTextBeginIndex) {
921
- // change start is before the open tag
922
- // Math.max(lastProcessedPlainTextTagEndIndex, startIndex) is used as startIndex may not be in [[previous tag].plainTextEndIndex - tag.plainTextBeginIndex] range
923
- const startChangeDiff = tag.plainTextBeginIndex - Math.max(lastProcessedPlainTextTagEndIndex, startIndex);
924
- result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex - startChangeDiff) + processedChange;
925
- processedChange = '';
926
- if (oldPlainTextEndIndex <= tag.plainTextBeginIndex) {
927
- // the whole change is before tag start
928
- // mentionTag length can be ignored here as the change is before the tag
929
- const endChangeDiff = tag.plainTextBeginIndex - oldPlainTextEndIndex;
930
- lastProcessedHTMLIndex = tag.openTagIndex - endChangeDiff;
931
- // the change is handled; exit
932
- break;
933
- }
934
- else {
935
- // change continues in the tag
936
- lastProcessedHTMLIndex = tag.openTagIndex;
937
- // proceed to the next check
938
- }
939
- }
940
- const closingTagInfo = getTagClosingTagInfo(tag);
941
- if (startIndex <= closingTagInfo.plainTextEndIndex) {
942
- // change started before the end tag
943
- if (startIndex <= tag.plainTextBeginIndex && oldPlainTextEndIndex === closingTagInfo.plainTextEndIndex) {
944
- // the change is a tag or starts before the tag
945
- // tag should be removed, no matter if there are sub-tags
946
- result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
947
- processedChange = '';
948
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
949
- // the change is handled; exit
950
- break;
951
- }
952
- else if (startIndex >= tag.plainTextBeginIndex && oldPlainTextEndIndex <= closingTagInfo.plainTextEndIndex) {
953
- // the change is between the tag
954
- if (isMentionTag) {
955
- if (change !== '') {
956
- if (startIndex !== tag.plainTextBeginIndex && startIndex !== closingTagInfo.plainTextEndIndex) {
957
- // mention tag should be deleted when user tries to edit it in the middle
958
- result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
959
- changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
960
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
961
- }
962
- else if (startIndex === tag.plainTextBeginIndex) {
963
- // non empty change at the beginning of the mention tag to be added before the mention tag
964
- result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
965
- changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
966
- lastProcessedHTMLIndex = tag.openTagIndex;
967
- }
968
- else if (startIndex === closingTagInfo.plainTextEndIndex) {
969
- // non empty change at the end of the mention tag to be added after the mention tag
970
- result +=
971
- htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength) +
972
- processedChange;
973
- changeNewEndIndex = closingTagInfo.plainTextEndIndex + processedChange.length;
974
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
975
- }
976
- processedChange = '';
977
- }
978
- else {
979
- const updateMentionTagResult = handleMentionTagUpdate({
980
- htmlText,
981
- oldPlainText,
982
- lastProcessedHTMLIndex,
983
- processedChange,
984
- change,
985
- tag,
986
- closeTagIdx: closingTagInfo.closeTagIdx,
987
- closeTagLength: closingTagInfo.closeTagLength,
988
- plainTextEndIndex: closingTagInfo.plainTextEndIndex,
989
- startIndex,
990
- oldPlainTextEndIndex,
991
- mentionTagLength
992
- });
993
- result += updateMentionTagResult.result;
994
- changeNewEndIndex = updateMentionTagResult.plainTextSelectionEndIndex;
995
- processedChange = updateMentionTagResult.updatedChange;
996
- lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
997
- }
998
- }
999
- else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
1000
- // with subtags
1001
- const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
1002
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
1003
- const updatedContent = updateHTML({
1004
- htmlText: tag.content,
1005
- oldPlainText,
1006
- newPlainText,
1007
- tags: tag.subTags,
1008
- startIndex,
1009
- oldPlainTextEndIndex,
1010
- change: processedChange,
1011
- mentionTrigger
1012
- });
1013
- result += stringBefore + updatedContent.updatedHTML;
1014
- changeNewEndIndex = updatedContent.updatedSelectionIndex;
1015
- }
1016
- else {
1017
- // no subtags
1018
- const startChangeDiff = startIndex - tag.plainTextBeginIndex;
1019
- result +=
1020
- htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff) +
1021
- processedChange;
1022
- processedChange = '';
1023
- if (oldPlainTextEndIndex < closingTagInfo.plainTextEndIndex) {
1024
- const endChangeDiff = oldPlainTextEndIndex - tag.plainTextBeginIndex;
1025
- lastProcessedHTMLIndex = tag.openTagIndex + tag.openTagBody.length + endChangeDiff;
1026
- }
1027
- else if (oldPlainTextEndIndex === closingTagInfo.plainTextEndIndex) {
1028
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
1029
- }
1030
- }
1031
- // the change is handled; exit
1032
- break;
1033
- }
1034
- else if (startIndex > tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
1035
- // the change started in the tag but finishes somewhere further
1036
- const startChangeDiff = startIndex - tag.plainTextBeginIndex - mentionTagLength;
1037
- if (isMentionTag) {
1038
- const updateMentionTagResult = handleMentionTagUpdate({
1039
- htmlText,
1040
- oldPlainText,
1041
- lastProcessedHTMLIndex,
1042
- processedChange: '',
1043
- change,
1044
- tag,
1045
- closeTagIdx: closingTagInfo.closeTagIdx,
1046
- closeTagLength: closingTagInfo.closeTagLength,
1047
- plainTextEndIndex: closingTagInfo.plainTextEndIndex,
1048
- startIndex,
1049
- oldPlainTextEndIndex,
1050
- mentionTagLength
1051
- });
1052
- result += updateMentionTagResult.result;
1053
- lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
1054
- // no need to handle plainTextSelectionEndIndex as the change will be added later
1055
- }
1056
- else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
1057
- // with subtags
1058
- const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
1059
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
1060
- const updatedContent = updateHTML({
1061
- htmlText: tag.content,
1062
- oldPlainText,
1063
- newPlainText,
1064
- tags: tag.subTags,
1065
- startIndex,
1066
- oldPlainTextEndIndex,
1067
- change: '',
1068
- mentionTrigger
1069
- });
1070
- result += stringBefore + updatedContent.updatedHTML;
1071
- }
1072
- else {
1073
- // no subtags
1074
- result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff);
1075
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
1076
- }
1077
- // proceed with the next calculations
1078
- }
1079
- else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
1080
- // the change starts before the tag and finishes after it
1081
- // tag should be removed, no matter if there are subtags
1082
- // no need to save anything between lastProcessedHTMLIndex and closeTagIdx + closeTagLength
1083
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
1084
- // proceed with the next calculations
1085
- }
1086
- else if (startIndex === tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
1087
- // the change starts in the tag and finishes after it
1088
- // tag should be removed, no matter if there are subtags
1089
- result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex);
1090
- // processedChange shouldn't be updated as it will be added after the tag
1091
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
1092
- // proceed with the next calculations
1093
- }
1094
- else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex < closingTagInfo.plainTextEndIndex) {
1095
- // the change starts before the tag and ends in a tag
1096
- if (isMentionTag) {
1097
- // mention tag
1098
- const updateMentionTagResult = handleMentionTagUpdate({
1099
- htmlText,
1100
- oldPlainText,
1101
- lastProcessedHTMLIndex,
1102
- processedChange: '',
1103
- change,
1104
- tag,
1105
- closeTagIdx: closingTagInfo.closeTagIdx,
1106
- closeTagLength: closingTagInfo.closeTagLength,
1107
- plainTextEndIndex: closingTagInfo.plainTextEndIndex,
1108
- startIndex,
1109
- oldPlainTextEndIndex,
1110
- mentionTagLength
1111
- });
1112
- changeNewEndIndex = updateMentionTagResult.plainTextSelectionEndIndex;
1113
- result += updateMentionTagResult.result;
1114
- lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
1115
- }
1116
- else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
1117
- // with subtags
1118
- const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
1119
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
1120
- const updatedContent = updateHTML({
1121
- htmlText: tag.content,
1122
- oldPlainText,
1123
- newPlainText,
1124
- tags: tag.subTags,
1125
- startIndex,
1126
- oldPlainTextEndIndex,
1127
- change: processedChange,
1128
- mentionTrigger
1129
- });
1130
- processedChange = '';
1131
- result += stringBefore + updatedContent.updatedHTML;
1132
- }
1133
- else {
1134
- // no subtags
1135
- result +=
1136
- htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length) + processedChange;
1137
- processedChange = '';
1138
- // oldPlainTextEndIndex already includes mentionTag length
1139
- const endChangeDiff = closingTagInfo.plainTextEndIndex - oldPlainTextEndIndex;
1140
- // as change may be before the end of the tag, we need to add the rest of the tag
1141
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx - endChangeDiff;
1142
- }
1143
- // the change is handled; exit
1144
- break;
1145
- }
1146
- lastProcessedPlainTextTagEndIndex = closingTagInfo.plainTextEndIndex;
1147
- }
1148
- if (i === tags.length - 1 && oldPlainTextEndIndex >= closingTagInfo.plainTextEndIndex) {
1149
- // the last tag should handle the end of the change if needed
1150
- // oldPlainTextEndIndex already includes mentionTag length
1151
- const endChangeDiff = oldPlainTextEndIndex - closingTagInfo.plainTextEndIndex;
1152
- if (startIndex >= closingTagInfo.plainTextEndIndex) {
1153
- const startChangeDiff = startIndex - closingTagInfo.plainTextEndIndex;
1154
- result +=
1155
- htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength + startChangeDiff) + processedChange;
1156
- }
1157
- else {
1158
- result +=
1159
- htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength) +
1160
- processedChange;
1161
- }
1162
- processedChange = '';
1163
- lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength + endChangeDiff;
1164
- // the change is handled; exit
1165
- // break is not required here as this is the last element but added for consistency
1166
- break;
1167
- }
1168
- }
1169
- if (lastProcessedHTMLIndex < htmlText.length) {
1170
- // add the rest of the html string
1171
- result += htmlText.substring(lastProcessedHTMLIndex);
1172
- }
1173
- return { updatedHTML: result, updatedSelectionIndex: changeNewEndIndex };
1174
- };
1175
- /* @conditional-compile-remove(mention) */
1176
- /**
1177
- * Given the oldText and newText, find the start index, old end index and new end index for the changes
1178
- *
1179
- * @private
1180
- * @param props - Props for finding stings diff indexes function.
1181
- * @returns Indexes for change start and ends in new and old texts. The old and new end indexes are exclusive.
1182
- */
1183
- const findStringsDiffIndexes = (props) => {
1184
- const { oldText, newText, previousSelectionStart, previousSelectionEnd, currentSelectionStart, currentSelectionEnd } = props;
1185
- const newTextLength = newText.length;
1186
- const oldTextLength = oldText.length;
1187
- // let changeStart = 0;
1188
- let newChangeEnd = newTextLength;
1189
- let oldChangeEnd = oldTextLength;
1190
- const previousSelectionStartValue = previousSelectionStart > -1 ? previousSelectionStart : oldTextLength;
1191
- const previousSelectionEndValue = previousSelectionEnd > -1 ? previousSelectionEnd : oldTextLength;
1192
- const currentSelectionStartValue = currentSelectionStart > -1 ? currentSelectionStart : newTextLength;
1193
- const currentSelectionEndValue = currentSelectionEnd > -1 ? currentSelectionEnd : newTextLength;
1194
- const changeStart = Math.min(previousSelectionStartValue, previousSelectionEndValue, currentSelectionStartValue, currentSelectionEndValue, newTextLength, oldTextLength);
1195
- if (oldTextLength < newTextLength) {
1196
- //insert or replacement
1197
- if (oldTextLength === changeStart) {
1198
- // when change was at the end of string
1199
- // change is found
1200
- newChangeEnd = newTextLength;
1201
- oldChangeEnd = oldTextLength;
1202
- }
1203
- else {
1204
- for (let i = 1; i < newTextLength && oldTextLength - i >= changeStart; i++) {
1205
- newChangeEnd = newTextLength - i - 1;
1206
- oldChangeEnd = oldTextLength - i - 1;
1207
- if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
1208
- // change is found
1209
- break;
1210
- }
1211
- }
1212
- // make indexes exclusive
1213
- newChangeEnd += 1;
1214
- oldChangeEnd += 1;
1215
- }
1216
- }
1217
- else if (oldTextLength > newTextLength) {
1218
- //deletion or replacement
1219
- if (newTextLength === changeStart) {
1220
- // when change was at the end of string
1221
- // change is found
1222
- newChangeEnd = newTextLength;
1223
- oldChangeEnd = oldTextLength;
1224
- }
1225
- else {
1226
- for (let i = 1; i < oldTextLength && newTextLength - i >= changeStart; i++) {
1227
- newChangeEnd = newTextLength - i - 1;
1228
- oldChangeEnd = oldTextLength - i - 1;
1229
- if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
1230
- // change is found
1231
- break;
1232
- }
1233
- }
1234
- // make indexes exclusive
1235
- newChangeEnd += 1;
1236
- oldChangeEnd += 1;
1237
- }
1238
- }
1239
- else {
1240
- // replacement
1241
- for (let i = 1; i < oldTextLength && oldTextLength - i >= changeStart; i++) {
1242
- newChangeEnd = newTextLength - i - 1;
1243
- oldChangeEnd = oldTextLength - i - 1;
1244
- if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
1245
- // change is found
1246
- break;
1247
- }
1248
- }
1249
- // make indexes exclusive if they aren't equal to the length of the string
1250
- if (newChangeEnd !== newText.length) {
1251
- newChangeEnd += 1;
1252
- }
1253
- if (oldChangeEnd !== oldText.length) {
1254
- oldChangeEnd += 1;
1255
- }
1256
- }
1257
- return { changeStart, oldChangeEnd, newChangeEnd };
1258
- };
1259
- /* @conditional-compile-remove(mention) */
1260
- /**
1261
- * Get the html string for the mention suggestion.
1262
- *
1263
- * @private
1264
- * @param suggestion - The mention suggestion.
1265
- * @param localeStrings - The locale strings.
1266
- * @returns The html string for the mention suggestion.
1267
- */
1268
- const htmlStringForMentionSuggestion = (suggestion, localeStrings) => {
1269
- const idHTML = ' id ="' + suggestion.id + '"';
1270
- const displayTextHTML = ' displayText ="' + suggestion.displayText + '"';
1271
- const displayText = getDisplayNameForMentionSuggestion(suggestion, localeStrings);
1272
- return '<' + MSFT_MENTION_TAG + idHTML + displayTextHTML + '>' + displayText + '</' + MSFT_MENTION_TAG + '>';
1273
- };
1274
- /* @conditional-compile-remove(mention) */
1275
- /**
1276
- * Get display name for the mention suggestion.
1277
- *
1278
- * @private
1279
- *
1280
- * @param suggestion - The mention suggestion.
1281
- * @param localeStrings - The locale strings.
1282
- * @returns The display name for the mention suggestion or display name placeholder if display name is empty.
1283
- */
1284
- const getDisplayNameForMentionSuggestion = (suggestion, localeStrings) => {
1285
- const displayNamePlaceholder = localeStrings.participantItem.displayNamePlaceholder;
1286
- return suggestion.displayText !== '' ? suggestion.displayText : displayNamePlaceholder !== null && displayNamePlaceholder !== void 0 ? displayNamePlaceholder : '';
1287
- };
1288
- /* @conditional-compile-remove(mention) */
1289
- /**
1290
- * Parse the text and return the tags and the plain text in one go
1291
- * @private
1292
- * @param text - The text to parse for HTML tags
1293
- * @param trigger The trigger to show for the mention tag in plain text
1294
- *
1295
- * @returns An array of tags and the plain text representation
1296
- */
1297
- const textToTagParser = (text, trigger) => {
1298
- var _a, _b;
1299
- const tags = []; // Tags passed back to the caller
1300
- const tagParseStack = []; // Local stack to use while parsing
1301
- let plainTextRepresentation = '';
1302
- let parseIndex = 0;
1303
- while (parseIndex < text.length) {
1304
- const foundHtmlTag = findNextHtmlTag(text, parseIndex);
1305
- if (!foundHtmlTag) {
1306
- if (parseIndex !== 0) {
1307
- // Add the remaining text to the plain text representation
1308
- plainTextRepresentation += text.substring(parseIndex);
1309
- }
1310
- else {
1311
- plainTextRepresentation = text;
1312
- }
1313
- break;
1314
- }
1315
- if (foundHtmlTag.type === 'open' || foundHtmlTag.type === 'self-closing') {
1316
- const nextTag = parseOpenTag(foundHtmlTag.content, foundHtmlTag.startIdx);
1317
- // Add the plain text between the last tag and this one found
1318
- plainTextRepresentation += text.substring(parseIndex, foundHtmlTag.startIdx);
1319
- nextTag.plainTextBeginIndex = plainTextRepresentation.length;
1320
- if (foundHtmlTag.type === 'open') {
1321
- tagParseStack.push(nextTag);
1322
- }
1323
- else {
1324
- nextTag.content = '';
1325
- nextTag.plainTextBeginIndex = plainTextRepresentation.length;
1326
- nextTag.plainTextEndIndex = plainTextRepresentation.length;
1327
- addTag(nextTag, tagParseStack, tags);
1328
- }
1329
- }
1330
- if (foundHtmlTag.type === 'close') {
1331
- const currentOpenTag = tagParseStack.pop();
1332
- const closeTagType = foundHtmlTag.content.substring(2, foundHtmlTag.content.length - 1).toLowerCase();
1333
- if (currentOpenTag && currentOpenTag.tagType === closeTagType) {
1334
- // Tag startIdx is absolute to the text. This is updated later to be relative to the parent tag
1335
- currentOpenTag.content = text.substring(currentOpenTag.openTagIndex + currentOpenTag.openTagBody.length, foundHtmlTag.startIdx);
1336
- // Insert the plain text pieces for the sub tags
1337
- if (currentOpenTag.tagType === MSFT_MENTION_TAG) {
1338
- plainTextRepresentation =
1339
- plainTextRepresentation.slice(0, currentOpenTag.plainTextBeginIndex) +
1340
- trigger +
1341
- plainTextRepresentation.slice(currentOpenTag.plainTextBeginIndex);
1342
- }
1343
- if (!currentOpenTag.subTags) {
1344
- plainTextRepresentation += currentOpenTag.content;
1345
- }
1346
- else if (currentOpenTag.subTags.length > 0) {
1347
- // Add text after the last tag
1348
- const lastSubTag = currentOpenTag.subTags[currentOpenTag.subTags.length - 1];
1349
- const startOfRemainingText = ((_a = lastSubTag.closingTagIndex) !== null && _a !== void 0 ? _a : lastSubTag.openTagIndex) + lastSubTag.tagType.length + 3;
1350
- const trailingText = currentOpenTag.content.substring(startOfRemainingText);
1351
- plainTextRepresentation += trailingText;
1352
- }
1353
- currentOpenTag.plainTextEndIndex = plainTextRepresentation.length;
1354
- addTag(currentOpenTag, tagParseStack, tags);
1355
- }
1356
- else {
1357
- throw new Error('Unexpected close tag found. Got "' +
1358
- closeTagType +
1359
- '" but expected "' +
1360
- ((_b = tagParseStack[tagParseStack.length - 1]) === null || _b === void 0 ? void 0 : _b.tagType) +
1361
- '"');
1362
- }
1363
- }
1364
- // Update parsing index; move past the end of the close tag
1365
- parseIndex = foundHtmlTag.startIdx + foundHtmlTag.content.length;
1366
- } // While parseIndex < text.length loop
1367
- return { tags, plainText: plainTextRepresentation };
1368
- };
1369
- /* @conditional-compile-remove(mention) */
1370
- const parseOpenTag = (tag, startIdx) => {
1371
- const tagType = tag
1372
- .substring(1, tag.length - 1)
1373
- .split(' ')[0]
1374
- .toLowerCase()
1375
- .replace('/', '');
1376
- return {
1377
- tagType,
1378
- openTagIndex: startIdx,
1379
- openTagBody: tag
1380
- };
1381
- };
1382
- /* @conditional-compile-remove(mention) */
1383
- const findNextHtmlTag = (text, startIndex) => {
1384
- const tagStartIndex = text.indexOf('<', startIndex);
1385
- if (tagStartIndex === -1) {
1386
- // No more tags
1387
- return undefined;
1388
- }
1389
- const tagEndIndex = text.indexOf('>', tagStartIndex);
1390
- if (tagEndIndex === -1) {
1391
- // No close tag
1392
- return undefined;
1393
- }
1394
- const tag = text.substring(tagStartIndex, tagEndIndex + 1);
1395
- let type = 'open';
1396
- if (tag[1] === '/') {
1397
- type = 'close';
1398
- }
1399
- else if (tag[tag.length - 2] === '/') {
1400
- type = 'self-closing';
1401
- }
1402
- return {
1403
- content: tag,
1404
- startIdx: tagStartIndex,
1405
- type
1406
- };
1407
- };
1408
- /* @conditional-compile-remove(mention) */
1409
- const addTag = (tag, parseStack, tags) => {
1410
- var _a;
1411
- // Add as sub-tag to the parent stack tag, if there is one
1412
- const parentTag = parseStack[parseStack.length - 1];
1413
- if (parentTag) {
1414
- // Adjust the open tag index to be relative to the parent tag
1415
- const parentContentStartIdx = parentTag.openTagIndex + parentTag.openTagBody.length;
1416
- const relativeIdx = tag.openTagIndex - parentContentStartIdx;
1417
- tag.openTagIndex = relativeIdx;
1418
- }
1419
- if (!tag.closingTagIndex) {
1420
- // If the tag is self-closing, the close tag is the same as the open tag
1421
- if (tag.openTagBody[tag.openTagBody.length - 2] === '/') {
1422
- tag.closingTagIndex = tag.openTagIndex;
1423
- }
1424
- else {
1425
- // Otherwise, the close tag index is the open tag index + the open tag body + the content length
1426
- tag.closingTagIndex = tag.openTagIndex + tag.openTagBody.length + ((_a = tag.content) !== null && _a !== void 0 ? _a : []).length;
1427
- }
1428
- }
1429
- // Put the tag where it belongs
1430
- if (!parentTag) {
1431
- tags.push(tag);
1432
- }
1433
- else {
1434
- if (!parentTag.subTags) {
1435
- parentTag.subTags = [tag];
1436
- }
1437
- else {
1438
- parentTag.subTags.push(tag);
1439
- }
1440
- }
1441
- };
1442
105
  //# sourceMappingURL=InputBoxComponent.js.map