UNPKG

communication-react-19

Version:

React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)

595 lines 35.5 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import React, { useState, useCallback, useRef } from 'react'; import { useEffect, useMemo } from 'react'; import { useLocale } from '../../localization'; import { Announcer } from '../Announcer'; import { TextField } from '@fluentui/react'; import { isEnterKeyEventFromCompositionSession, nullToUndefined } from '../utils'; import { findMentionTagForSelection, findNewSelectionIndexForMention, findStringsDiffIndexes, getDisplayNameForMentionSuggestion, getValidatedIndexInRange, htmlStringForMentionSuggestion, textToTagParser, updateHTML } from './mentionTagUtils'; import { Caret } from 'textarea-caret-ts'; import { _MentionPopover } from '../MentionPopover'; import { useDebouncedCallback } from 'use-debounce'; const DEFAULT_MENTION_TRIGGER = '@'; /** * @private */ export const TextFieldWithMention = (props) => { const { textFieldProps, dataUiId, textValue, onChange, textFieldRef, onKeyDown, onEnterKeyDown, supportNewline, mentionLookupOptions } = props; const inputBoxRef = useRef(null); // Current suggestion list, provided by the callback const [mentionSuggestions, setMentionSuggestions] = useState([]); // Current suggestion list, provided by the callback const [activeSuggestionIndex, setActiveSuggestionIndex] = useState(undefined); // Index of the current trigger character in the text field const [currentTriggerStartIndex, setCurrentTriggerStartIndex] = useState(-1); const [inputTextValue, setInputTextValue] = useState(''); // Internal value for text value prop const [internalTextValue, setInternalTextValue] = useState(''); const [tagsValue, setTagsValue] = useState([]); // Index of the previous selection start in the text field const [selectionStartValue, setSelectionStartValue] = useState(); // Index of the previous selection end in the text field const [selectionEndValue, setSelectionEndValue] = useState(); // Boolean value to check if onMouseDown event should be handled during select as selection range // for onMouseDown event is not updated yet and the selection range for mouse click/taps will be // updated in onSelect event if needed. const [shouldHandleOnMouseDownDuringSelect, setShouldHandleOnMouseDownDuringSelect] = useState(true); // Boolean flag to check if mouse/touch move event should be handled const [shouldHandleMoveEvent, setShouldHandleMoveEvent] = useState(false); // Indexes of start of touch/mouse selection const [interactionStartSelection, setInteractionStartSelection] = useState(); // Caret position in the text field const [caretPosition, setCaretPosition] = useState(undefined); // Index of where the caret is in the text field const [caretIndex, setCaretIndex] = useState(undefined); const localeStrings = useLocale().strings; // Set mention suggestions const updateMentionSuggestions = useCallback((suggestions) => { setMentionSuggestions(suggestions); }, [setMentionSuggestions]); useEffect(() => { setInternalTextValue(textValue); // update mention suggestions before the next render cycle updateMentionSuggestions([]); }, [textValue, updateMentionSuggestions]); // Parse the text and get the plain text version to display in the input box useEffect(() => { const trigger = (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) || DEFAULT_MENTION_TRIGGER; const parsedHTMLData = textToTagParser(internalTextValue, trigger); setInputTextValue(parsedHTMLData.plainText); setTagsValue(parsedHTMLData.tags); updateMentionSuggestions([]); }, [internalTextValue, mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger, updateMentionSuggestions]); useEffect(() => { var _a; // effect for caret index update if (caretIndex === undefined || textFieldRef === undefined || (textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === undefined) { return; } // get validated caret index between 0 and inputTextValue.length otherwise caret will be set to incorrect index const updatedCaretIndex = getValidatedIndexInRange({ min: 0, max: inputTextValue.length, currentValue: caretIndex }); (_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.setSelectionRange(updatedCaretIndex, updatedCaretIndex); setSelectionStartValue(updatedCaretIndex); setSelectionEndValue(updatedCaretIndex); }, [caretIndex, inputTextValue, textFieldRef, setSelectionStartValue, setSelectionEndValue]); const onSuggestionSelected = useCallback((suggestion) => { var _a, _b, _c; let selectionEnd = ((_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.selectionEnd) || -1; if (selectionEnd < 0) { selectionEnd = 0; } else if (selectionEnd > inputTextValue.length) { selectionEnd = inputTextValue.length; } const oldPlainText = inputTextValue; const mention = htmlStringForMentionSuggestion(suggestion, localeStrings); // update plain text with the mention html text const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : DEFAULT_MENTION_TRIGGER; // update html text with updated plain text const updatedContent = updateHTML({ htmlText: internalTextValue, oldPlainText, tags: tagsValue, startIndex: currentTriggerStartIndex, oldPlainTextEndIndex: selectionEnd, change: mention, mentionTrigger: triggerText }); setInternalTextValue(updatedContent.updatedHTML); const displayName = getDisplayNameForMentionSuggestion(suggestion, localeStrings); const newCaretIndex = currentTriggerStartIndex + displayName.length + triggerText.length; // move the caret in the text field to the end of the mention plain text setCaretIndex(newCaretIndex); setSelectionEndValue(newCaretIndex); setSelectionStartValue(newCaretIndex); setCurrentTriggerStartIndex(-1); updateMentionSuggestions([]); // set focus back to text field (_c = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _c === void 0 ? void 0 : _c.focus(); setActiveSuggestionIndex(undefined); onChange && onChange(undefined, updatedContent.updatedHTML); }, [ textFieldRef, inputTextValue, currentTriggerStartIndex, mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger, onChange, internalTextValue, tagsValue, updateMentionSuggestions, localeStrings ]); const onTextFieldKeyDown = useCallback((ev) => { // caretIndex should be set to undefined when the user is typing setCaretIndex(undefined); // shouldHandleOnMouseDownDuringSelect should be set to false after the last mouse down event. // it shouldn't be updated in onMouseUp // as onMouseUp can be triggered before or after onSelect event // because its order depends on mouse events not selection. setShouldHandleOnMouseDownDuringSelect(false); if (isEnterKeyEventFromCompositionSession(ev.nativeEvent)) { return; } let isActiveSuggestionIndexUpdated = false; if (mentionSuggestions.length > 0) { if (ev.key === 'ArrowUp') { ev.preventDefault(); const newActiveIndex = activeSuggestionIndex === undefined ? mentionSuggestions.length - 1 : Math.max(activeSuggestionIndex - 1, 0); setActiveSuggestionIndex(newActiveIndex); isActiveSuggestionIndexUpdated = true; } else if (ev.key === 'ArrowDown') { ev.preventDefault(); const newActiveIndex = activeSuggestionIndex === undefined ? 0 : Math.min(activeSuggestionIndex + 1, mentionSuggestions.length - 1); setActiveSuggestionIndex(newActiveIndex); isActiveSuggestionIndexUpdated = true; } else if (ev.key === 'Escape') { updateMentionSuggestions([]); // reset active suggestion index when suggestions are closed setActiveSuggestionIndex(undefined); isActiveSuggestionIndexUpdated = true; } } if (ev.key === 'Enter' && (ev.shiftKey === false || !supportNewline)) { ev.preventDefault(); // If we are looking up a mention, select the focused suggestion if (mentionSuggestions.length > 0 && activeSuggestionIndex !== undefined) { const selectedMention = mentionSuggestions[activeSuggestionIndex]; if (selectedMention) { onSuggestionSelected(selectedMention); return; } } onEnterKeyDown && onEnterKeyDown(); } else if (!isActiveSuggestionIndexUpdated) { // Update the active suggestion index if the user is typing, // otherwise the focus will be lost setActiveSuggestionIndex(undefined); } onKeyDown && onKeyDown(ev); }, [ onEnterKeyDown, onKeyDown, supportNewline, mentionSuggestions, activeSuggestionIndex, onSuggestionSelected, updateMentionSuggestions ]); const debouncedQueryUpdate = useDebouncedCallback((query) => __awaiter(void 0, void 0, void 0, function* () { var _a; let suggestions = (_a = (yield (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.onQueryUpdated(query)))) !== null && _a !== void 0 ? _a : []; suggestions = suggestions.filter((suggestion) => suggestion.displayText.trim() !== ''); if (suggestions.length === 0) { setActiveSuggestionIndex(undefined); } else if (activeSuggestionIndex === undefined) { // Set the active to the first, if it's not already set setActiveSuggestionIndex(0); } updateMentionSuggestions(suggestions); }), 500); // Update selections index in mention to navigate by words const updateSelectionIndexesWithMentionIfNeeded = useCallback(({ event, inputTextValue, selectionEndValue, selectionStartValue, tagsValue }) => { var _a, _b, _c; let updatedStartIndex = event.currentTarget.selectionStart; let updatedEndIndex = event.currentTarget.selectionEnd; if (event.currentTarget.selectionStart === event.currentTarget.selectionEnd && event.currentTarget.selectionStart !== null && event.currentTarget.selectionStart !== -1) { // just a caret movement/usual typing or deleting const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart); // don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined && event.currentTarget.selectionStart > mentionTag.plainTextBeginIndex && event.currentTarget.selectionStart < ((_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex)) { // get updated selection index const newSelectionIndex = findNewSelectionIndexForMention({ tag: mentionTag, textValue: inputTextValue, currentSelectionIndex: event.currentTarget.selectionStart, previousSelectionIndex: selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : inputTextValue.length }); updatedStartIndex = newSelectionIndex; updatedEndIndex = newSelectionIndex; } } else if (event.currentTarget.selectionStart !== event.currentTarget.selectionEnd) { // Both e.currentTarget.selectionStart !== selectionStartValue and e.currentTarget.selectionEnd !== selectionEndValue can be true when a user selects a text by double click if (event.currentTarget.selectionStart !== null && event.currentTarget.selectionStart !== selectionStartValue) { // the selection start is changed const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart); // don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined && event.currentTarget.selectionStart > mentionTag.plainTextBeginIndex && event.currentTarget.selectionStart < ((_b = mentionTag.plainTextEndIndex) !== null && _b !== void 0 ? _b : mentionTag.plainTextBeginIndex)) { updatedStartIndex = findNewSelectionIndexForMention({ tag: mentionTag, textValue: inputTextValue, currentSelectionIndex: event.currentTarget.selectionStart, previousSelectionIndex: selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : inputTextValue.length }); } } if (event.currentTarget.selectionEnd !== null && event.currentTarget.selectionEnd !== selectionEndValue) { // the selection end is changed const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionEnd); // don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined && event.currentTarget.selectionEnd > mentionTag.plainTextBeginIndex && event.currentTarget.selectionEnd < ((_c = mentionTag.plainTextEndIndex) !== null && _c !== void 0 ? _c : mentionTag.plainTextBeginIndex)) { updatedEndIndex = findNewSelectionIndexForMention({ tag: mentionTag, textValue: inputTextValue, currentSelectionIndex: event.currentTarget.selectionEnd, previousSelectionIndex: selectionEndValue !== null && selectionEndValue !== void 0 ? selectionEndValue : inputTextValue.length }); } } } // e.currentTarget.selectionDirection should be set to handle shift + arrow keys if (event.currentTarget.selectionDirection === null) { event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex); } else { event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex, event.currentTarget.selectionDirection); } setSelectionStartValue(nullToUndefined(updatedStartIndex)); setSelectionEndValue(nullToUndefined(updatedEndIndex)); }, [setSelectionStartValue, setSelectionEndValue]); const handleOnSelect = useCallback(({ event, inputTextValue, tags, shouldHandleOnMouseDownDuringSelect, selectionStartValue, selectionEndValue, interactionStartSelection }) => { var _a; if (event.currentTarget.selectionStart === 0 && event.currentTarget.selectionEnd === inputTextValue.length) { // entire text is selected, no need to change anything setSelectionStartValue(event.currentTarget.selectionStart); setSelectionEndValue(event.currentTarget.selectionEnd); setInteractionStartSelection(undefined); setShouldHandleOnMouseDownDuringSelect(false); } else if (shouldHandleOnMouseDownDuringSelect) { if (interactionStartSelection !== undefined && (interactionStartSelection.start !== event.currentTarget.selectionStart || interactionStartSelection.end !== event.currentTarget.selectionEnd)) { // selection was changed by mouse // for mouse selection only, it's possible to start selection in the middle of a word in a mention // because of this when event.currentTarget.selectionStart === mouseMoveStartPoint.start // selectionStartValue for updateSelectionIndexesWithMentionIfNeeded should be set // to the end of the input to mimic selection from right to left for the left selection index const updatedSelectionStartValue = event.currentTarget.selectionStart === interactionStartSelection.start ? inputTextValue.length : interactionStartSelection.start; // selectionStart is always less than selectionEnd so sometimes selectionEnd is user's start of the selection // so when event.currentTarget.selectionEnd === mouseMoveStartPoint.end // selectionEndValue for updateSelectionIndexesWithMentionIfNeeded should be set // to the beginning of the input to mimic selection from left to right for the right selection index const updatedSelectionEndValue = event.currentTarget.selectionEnd === interactionStartSelection.end ? 0 : interactionStartSelection.end; updateSelectionIndexesWithMentionIfNeeded({ event, inputTextValue, selectionStartValue: updatedSelectionStartValue, selectionEndValue: updatedSelectionEndValue, tagsValue: tags }); setInteractionStartSelection(undefined); setShouldHandleOnMouseDownDuringSelect(false); } else if (event.currentTarget.selectionStart !== null && event.currentTarget.selectionEnd !== null) { // on select was triggered by mouse down/up with no movement const mentionTag = findMentionTagForSelection(tags, event.currentTarget.selectionStart); if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) { // handle mention click by selecting the whole mention // if the selection is not on the bounds of the mention // disable selection for clicks on mention bounds const mentionEndIndex = (_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex; if (event.currentTarget.selectionStart !== event.currentTarget.selectionEnd && event.currentTarget.selectionEnd > mentionEndIndex) { // handle triple click when the text starts from mention if (event.currentTarget.selectionDirection === null) { event.currentTarget.setSelectionRange(mentionTag.plainTextBeginIndex, event.currentTarget.selectionEnd); } else { event.currentTarget.setSelectionRange(mentionTag.plainTextBeginIndex, event.currentTarget.selectionEnd, event.currentTarget.selectionDirection); } setSelectionStartValue(mentionTag.plainTextBeginIndex); setSelectionEndValue(event.currentTarget.selectionEnd); } else if (event.currentTarget.selectionStart !== event.currentTarget.selectionEnd || (event.currentTarget.selectionStart !== mentionTag.plainTextBeginIndex && event.currentTarget.selectionStart !== mentionEndIndex)) { if (event.currentTarget.selectionDirection === null) { event.currentTarget.setSelectionRange(mentionTag.plainTextBeginIndex, mentionEndIndex); } else { event.currentTarget.setSelectionRange(mentionTag.plainTextBeginIndex, mentionEndIndex, event.currentTarget.selectionDirection); } setSelectionStartValue(mentionTag.plainTextBeginIndex); setSelectionEndValue(mentionEndIndex); } else { // bounds of the mention were selected setSelectionStartValue(event.currentTarget.selectionStart); setSelectionEndValue(event.currentTarget.selectionEnd); } } else { // not a mention tag setSelectionStartValue(event.currentTarget.selectionStart); setSelectionEndValue(nullToUndefined(event.currentTarget.selectionEnd)); } setInteractionStartSelection(undefined); } } else { // selection was changed by keyboard updateSelectionIndexesWithMentionIfNeeded({ event, inputTextValue, selectionStartValue, selectionEndValue, tagsValue: tags }); } }, [updateSelectionIndexesWithMentionIfNeeded, setSelectionStartValue, setSelectionEndValue]); const handleOnChange = useCallback((_b) => __awaiter(void 0, [_b], void 0, function* ({ currentSelectionEnd, currentSelectionStart, currentTriggerStartIndex, event, htmlTextValue, inputTextValue, previousSelectionEnd, previousSelectionStart, tagsValue, updatedValue }) { var _c; debouncedQueryUpdate.cancel(); if (event.currentTarget === null) { return; } // handle backspace change // onSelect is not called for backspace as selection is not changed and local caret index is outdated setCaretIndex(undefined); const newValue = updatedValue !== null && updatedValue !== void 0 ? updatedValue : ''; const triggerText = (_c = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _c !== void 0 ? _c : DEFAULT_MENTION_TRIGGER; const newTextLength = newValue.length; // updating indexes to set between 0 and text length, otherwise selectionRange won't be set correctly const currentSelectionEndValue = getValidatedIndexInRange({ min: 0, max: newTextLength, currentValue: currentSelectionEnd }); const currentSelectionStartValue = getValidatedIndexInRange({ min: 0, max: newTextLength, currentValue: currentSelectionStart }); const previousSelectionStartValue = getValidatedIndexInRange({ min: 0, max: inputTextValue.length, currentValue: previousSelectionStart }); const previousSelectionEndValue = getValidatedIndexInRange({ min: 0, max: inputTextValue.length, currentValue: previousSelectionEnd }); // If we are enabled for lookups, if (mentionLookupOptions !== undefined) { // Look at the range of the change for a trigger character const triggerPriorIndex = newValue.lastIndexOf(triggerText, currentSelectionEndValue - 1); // Update the caret position, used for positioning the suggestions popover const textField = event.currentTarget; const relativePosition = Caret.getRelativePosition(textField); if (textField.scrollHeight > textField.clientHeight) { relativePosition.top -= textField.scrollTop; } setCaretPosition(relativePosition); if (triggerPriorIndex !== undefined) { // trigger is found const symbolBeforeTrigger = newValue.substring(triggerPriorIndex - 1, triggerPriorIndex); const isSpaceBeforeTrigger = symbolBeforeTrigger === ' '; // check if \r (Carriage Return), \n (Line Feed) or \r\n (End Of Line) is before the trigger const isNewLineBeforeTrigger = /\r|\n/.exec(symbolBeforeTrigger); const wordAtSelection = newValue.substring(triggerPriorIndex, currentSelectionEndValue); let tagIndex = currentTriggerStartIndex; if (!isSpaceBeforeTrigger && triggerPriorIndex !== 0 && isNewLineBeforeTrigger === null) { // no space before the trigger, it's not a beginning of the line and no new line before <- continuation of the previous word tagIndex = -1; setCurrentTriggerStartIndex(tagIndex); } else if (wordAtSelection === triggerText) { // start of the mention tagIndex = currentSelectionEndValue - triggerText.length; if (tagIndex < 0) { tagIndex = 0; } setCurrentTriggerStartIndex(tagIndex); } if (tagIndex === -1) { updateMentionSuggestions([]); } else { // In the middle of a @mention lookup if (tagIndex > -1) { const query = wordAtSelection.substring(triggerText.length, wordAtSelection.length); if (query !== undefined) { yield debouncedQueryUpdate(query); } } } } } const { changeStart, oldChangeEnd, newChangeEnd } = findStringsDiffIndexes({ oldText: inputTextValue, newText: newValue, previousSelectionStart: previousSelectionStartValue, previousSelectionEnd: previousSelectionEndValue, currentSelectionStart: currentSelectionStartValue, currentSelectionEnd: currentSelectionEndValue }); const change = newValue.substring(changeStart, newChangeEnd); const updatedContent = updateHTML({ htmlText: htmlTextValue, oldPlainText: inputTextValue, tags: tagsValue, startIndex: changeStart, oldPlainTextEndIndex: oldChangeEnd, change, mentionTrigger: triggerText }); setInternalTextValue(updatedContent.updatedHTML); // update caret index if needed if (updatedContent.updatedSelectionIndex !== undefined) { setCaretIndex(updatedContent.updatedSelectionIndex); setSelectionEndValue(updatedContent.updatedSelectionIndex); setSelectionStartValue(updatedContent.updatedSelectionIndex); } onChange && onChange(event, updatedContent.updatedHTML); }), [debouncedQueryUpdate, mentionLookupOptions, onChange, updateMentionSuggestions]); // Adjust the selection range based on a mouse / touch interaction const handleOnMove = useCallback(({ event, selectionStartValue, selectionEndValue, interactionStartSelection, shouldHandleMoveEvent }) => { if (shouldHandleMoveEvent && interactionStartSelection === undefined && (event.currentTarget.selectionStart !== selectionStartValue || event.currentTarget.selectionEnd !== selectionEndValue)) { setInteractionStartSelection({ start: nullToUndefined(event.currentTarget.selectionStart), end: nullToUndefined(event.currentTarget.selectionEnd) }); } }, []); // Adjust the selection range based on a mouse / touch interaction const handleOnInteractionStarted = useCallback(() => { // reset caret index as a new selection is started or cursor position will be changed setCaretIndex(undefined); setInteractionStartSelection(undefined); setShouldHandleMoveEvent(true); setShouldHandleOnMouseDownDuringSelect(true); }, []); // Adjust the selection range based on a mouse / touch interaction const handleOnInteractionCompleted = useCallback(() => { setShouldHandleMoveEvent(false); }, []); const announcerText = useMemo(() => { if (activeSuggestionIndex === undefined) { return undefined; } const currentMention = mentionSuggestions[activeSuggestionIndex !== null && activeSuggestionIndex !== void 0 ? activeSuggestionIndex : 0]; return currentMention && (currentMention === null || currentMention === void 0 ? void 0 : currentMention.displayText.length) > 0 ? currentMention === null || currentMention === void 0 ? void 0 : currentMention.displayText : localeStrings.participantItem.displayNamePlaceholder; }, [activeSuggestionIndex, mentionSuggestions, localeStrings.participantItem.displayNamePlaceholder]); return (React.createElement(React.Fragment, null, 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: () => { updateMentionSuggestions([]); } })), announcerText !== undefined && React.createElement(Announcer, { announcementString: announcerText, ariaLive: 'polite' }), React.createElement(TextField, Object.assign({}, textFieldProps, { "data-ui-id": dataUiId, value: inputTextValue, onChange: (e, newValue) => { // Remove when switching to react 17+, currently needed because of https://legacy.reactjs.org/docs/legacy-event-pooling.html // Prevents React from resetting event's properties e.persist(); setInputTextValue(newValue !== null && newValue !== void 0 ? newValue : ''); handleOnChange({ event: e, tagsValue, htmlTextValue: internalTextValue, inputTextValue, currentTriggerStartIndex, previousSelectionStart: nullToUndefined(selectionStartValue), previousSelectionEnd: nullToUndefined(selectionEndValue), currentSelectionStart: nullToUndefined(e.currentTarget.selectionStart), currentSelectionEnd: nullToUndefined(e.currentTarget.selectionEnd), updatedValue: newValue }); }, onSelect: (e) => { // update selection if needed if (caretIndex !== undefined) { // sometimes setting selectionRage in effect for updating caretIndex doesn't work as expected and // onSelect still returns outdated value for cursor position // e.g. when user select some text and a first name in a mention then delete or type something else if (caretIndex !== e.currentTarget.selectionStart || caretIndex !== e.currentTarget.selectionEnd) { e.currentTarget.setSelectionRange(caretIndex, caretIndex); } // caret index should not be set to undefined here // as it will cause issues when suggestion is selected by mouse // caret index will be set to undefined during keyboard/mouse or touch interactions return; } handleOnSelect({ event: e, inputTextValue, shouldHandleOnMouseDownDuringSelect, selectionEndValue, selectionStartValue, tags: tagsValue, interactionStartSelection }); }, onMouseDown: () => { // as events order is onMouseDown -> onMouseMove -> onMouseUp -> onSelect -> onClick // onClick and onMouseDown can't handle clicking on mention event because // onMouseDown doesn't have correct selectionRange yet and // onClick already has wrong range as it's called after onSelect that updates the selection range // so we need to handle onMouseDown to prevent onSelect default behavior handleOnInteractionStarted(); }, onMouseMove: (event) => { handleOnMove({ event, selectionStartValue, selectionEndValue, interactionStartSelection, shouldHandleMoveEvent }); }, onMouseUp: () => { handleOnInteractionCompleted(); }, onTouchStart: () => { handleOnInteractionStarted(); }, onTouchMove: (event) => { handleOnMove({ event, selectionStartValue, selectionEndValue, interactionStartSelection, shouldHandleMoveEvent }); }, onTouchEnd: () => { handleOnInteractionCompleted; }, onBlur: () => { // setup shouldHandleOnMouseDownDuringSelect to false when text field loses focus // as the click should be handled by text field anymore setShouldHandleOnMouseDownDuringSelect(false); }, onKeyDown: onTextFieldKeyDown, elementRef: inputBoxRef })))); }; //# sourceMappingURL=TextFieldWithMention.js.map