@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.
- package/dist/dist-cjs/communication-react/index.js +1457 -1484
- package/dist/dist-cjs/communication-react/index.js.map +1 -1
- package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js +1 -1
- package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/InputBoxComponent.js +38 -1375
- package/dist/dist-esm/react-components/src/components/InputBoxComponent.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/TextFieldWithMention/TextFieldWithMention.d.ts +41 -0
- package/dist/dist-esm/react-components/src/components/TextFieldWithMention/TextFieldWithMention.js +554 -0
- package/dist/dist-esm/react-components/src/components/TextFieldWithMention/TextFieldWithMention.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/TextFieldWithMention/mentionTagUtils.d.ts +167 -0
- package/dist/dist-esm/react-components/src/components/TextFieldWithMention/mentionTagUtils.js +780 -0
- package/dist/dist-esm/react-components/src/components/TextFieldWithMention/mentionTagUtils.js.map +1 -0
- package/package.json +8 -8
@@ -167,7 +167,7 @@ const _toCommunicationIdentifier = (id) => {
|
|
167
167
|
// Copyright (c) Microsoft Corporation.
|
168
168
|
// Licensed under the MIT license.
|
169
169
|
// GENERATED FILE. DO NOT EDIT MANUALLY.
|
170
|
-
var telemetryVersion = '1.5.1-alpha-
|
170
|
+
var telemetryVersion = '1.5.1-alpha-202306070014';
|
171
171
|
|
172
172
|
// Copyright (c) Microsoft Corporation.
|
173
173
|
/**
|
@@ -5808,32 +5808,6 @@ const DEFAULT_COMPONENT_ICONS = {
|
|
5808
5808
|
ChangeSpokenLanguageIcon: React__default['default'].createElement(reactIcons.PersonVoice20Regular, null)
|
5809
5809
|
};
|
5810
5810
|
|
5811
|
-
// Copyright (c) Microsoft Corporation.
|
5812
|
-
/**
|
5813
|
-
* @internal
|
5814
|
-
* Announcer component to maker aria announcements on actions
|
5815
|
-
*/
|
5816
|
-
const Announcer$1 = (props) => {
|
5817
|
-
const { announcementString, ariaLive } = props;
|
5818
|
-
return React__default['default'].createElement(react.Stack, { "aria-label": announcementString, "aria-live": ariaLive, styles: announcerStyles });
|
5819
|
-
};
|
5820
|
-
/**
|
5821
|
-
* Styles to hide the announcer from view but still existing on the DOM tree it so that narration can happen.
|
5822
|
-
*/
|
5823
|
-
const announcerStyles = {
|
5824
|
-
root: {
|
5825
|
-
position: 'absolute',
|
5826
|
-
width: '1px',
|
5827
|
-
height: '1px',
|
5828
|
-
padding: 0,
|
5829
|
-
margin: '-1px',
|
5830
|
-
overflow: 'hidden',
|
5831
|
-
clip: 'rect(0,0,0,0)',
|
5832
|
-
whiteSpace: 'nowrap',
|
5833
|
-
border: 0
|
5834
|
-
}
|
5835
|
-
};
|
5836
|
-
|
5837
5811
|
// Copyright (c) Microsoft Corporation.
|
5838
5812
|
/**
|
5839
5813
|
* @private
|
@@ -5966,1605 +5940,1604 @@ const getPerceptualBrightnessOfHexColor = (hexColor) => {
|
|
5966
5940
|
|
5967
5941
|
// Copyright (c) Microsoft Corporation.
|
5968
5942
|
/**
|
5969
|
-
* @
|
5970
|
-
*
|
5971
|
-
*/
|
5972
|
-
const CHAT_CONTAINER_ZINDEX$1 = 1;
|
5973
|
-
/**
|
5974
|
-
* @private
|
5975
|
-
*/
|
5976
|
-
const mentionPopoverContainerStyle = (theme) => react.mergeStyles({
|
5977
|
-
boxShadow: theme.effects.elevation16,
|
5978
|
-
background: theme.semanticColors.bodyBackground,
|
5979
|
-
overflow: 'visible',
|
5980
|
-
// zIndex to set the mentionPopover above the chat container
|
5981
|
-
zIndex: CHAT_CONTAINER_ZINDEX$1 + 1
|
5982
|
-
});
|
5983
|
-
/**
|
5984
|
-
* @private
|
5943
|
+
* @internal
|
5944
|
+
* Announcer component to maker aria announcements on actions
|
5985
5945
|
*/
|
5986
|
-
const
|
5987
|
-
|
5988
|
-
|
5989
|
-
color: theme.palette.neutralSecondary,
|
5990
|
-
margin: '0.5rem 1rem 0.25rem',
|
5991
|
-
fontSize: theme.fonts.smallPlus.fontSize
|
5992
|
-
}
|
5993
|
-
};
|
5946
|
+
const Announcer$1 = (props) => {
|
5947
|
+
const { announcementString, ariaLive } = props;
|
5948
|
+
return React__default['default'].createElement(react.Stack, { "aria-label": announcementString, "aria-live": ariaLive, styles: announcerStyles });
|
5994
5949
|
};
|
5995
5950
|
/**
|
5996
|
-
*
|
5951
|
+
* Styles to hide the announcer from view but still existing on the DOM tree it so that narration can happen.
|
5997
5952
|
*/
|
5998
|
-
|
5999
|
-
|
6000
|
-
|
6001
|
-
|
6002
|
-
|
5953
|
+
const announcerStyles = {
|
5954
|
+
root: {
|
5955
|
+
position: 'absolute',
|
5956
|
+
width: '1px',
|
5957
|
+
height: '1px',
|
5958
|
+
padding: 0,
|
5959
|
+
margin: '-1px',
|
5960
|
+
overflow: 'hidden',
|
5961
|
+
clip: 'rect(0,0,0,0)',
|
5962
|
+
whiteSpace: 'nowrap',
|
5963
|
+
border: 0
|
5964
|
+
}
|
5965
|
+
};
|
5966
|
+
|
5967
|
+
// Copyright (c) Microsoft Corporation.
|
5968
|
+
// Licensed under the MIT license.
|
5969
|
+
const MSFT_MENTION_TAG = 'msft-mention';
|
6003
5970
|
/**
|
5971
|
+
* Get validated value for index between min and max values. If currentValue is not defined, -1 will be used instead.
|
5972
|
+
*
|
6004
5973
|
* @private
|
5974
|
+
* @param props - Props for finding a valid index in range.
|
5975
|
+
* @returns Valid index in the range.
|
6005
5976
|
*/
|
6006
|
-
const
|
6007
|
-
|
6008
|
-
|
6009
|
-
|
5977
|
+
const getValidatedIndexInRange = (props) => {
|
5978
|
+
const { min, max, currentValue } = props;
|
5979
|
+
let updatedValue = currentValue !== null && currentValue !== void 0 ? currentValue : -1;
|
5980
|
+
updatedValue = Math.max(min, updatedValue);
|
5981
|
+
updatedValue = Math.min(updatedValue, max);
|
5982
|
+
return updatedValue;
|
5983
|
+
};
|
6010
5984
|
/**
|
5985
|
+
* Find mention tag for selection if exists.
|
5986
|
+
*
|
6011
5987
|
* @private
|
5988
|
+
* @param tags - Existing list of tags.
|
5989
|
+
* @param selection - Selection index.
|
5990
|
+
* @returns Mention tag if exists, otherwise undefined.
|
6012
5991
|
*/
|
6013
|
-
const
|
6014
|
-
|
6015
|
-
|
6016
|
-
|
6017
|
-
|
5992
|
+
const findMentionTagForSelection = (tags, selection) => {
|
5993
|
+
let mentionTag = undefined;
|
5994
|
+
tags.every((tag) => {
|
5995
|
+
const closingTagInfo = getTagClosingTagInfo(tag);
|
5996
|
+
if (tag.plainTextBeginIndex !== undefined && tag.plainTextBeginIndex > selection) {
|
5997
|
+
// no need to check further as the selection is before the tag
|
5998
|
+
return false;
|
5999
|
+
}
|
6000
|
+
else if (tag.plainTextBeginIndex !== undefined &&
|
6001
|
+
tag.plainTextBeginIndex <= selection &&
|
6002
|
+
selection <= closingTagInfo.plainTextEndIndex) {
|
6003
|
+
// no need to check if tag doesn't contain selection
|
6004
|
+
if (tag.subTags !== undefined && tag.subTags.length !== 0) {
|
6005
|
+
const selectedTag = findMentionTagForSelection(tag.subTags, selection);
|
6006
|
+
if (selectedTag !== undefined) {
|
6007
|
+
mentionTag = selectedTag;
|
6008
|
+
return false;
|
6009
|
+
}
|
6010
|
+
}
|
6011
|
+
else if (tag.tagType === MSFT_MENTION_TAG) {
|
6012
|
+
mentionTag = tag;
|
6013
|
+
return false;
|
6014
|
+
}
|
6018
6015
|
}
|
6016
|
+
return true;
|
6019
6017
|
});
|
6018
|
+
return mentionTag;
|
6020
6019
|
};
|
6021
6020
|
/**
|
6021
|
+
* Get the indices of the word for the selection.
|
6022
6022
|
* @private
|
6023
|
+
*
|
6023
6024
|
*/
|
6024
|
-
const
|
6025
|
-
|
6026
|
-
|
6027
|
-
|
6028
|
-
|
6029
|
-
|
6030
|
-
|
6031
|
-
|
6032
|
-
|
6025
|
+
const rangeOfWordInSelection = ({ textInput, selectionStart, selectionEnd, tag }) => {
|
6026
|
+
var _a;
|
6027
|
+
if (tag.plainTextBeginIndex === undefined) {
|
6028
|
+
return { start: selectionStart, end: selectionEnd === undefined ? selectionStart : selectionEnd };
|
6029
|
+
}
|
6030
|
+
// Look at start word index and optionally end word index.
|
6031
|
+
// Select combination of the two and return the range.
|
6032
|
+
let start = selectionStart;
|
6033
|
+
let end = selectionEnd === undefined ? selectionStart : selectionEnd;
|
6034
|
+
const firstWordStartIndex = textInput.lastIndexOf(' ', selectionStart);
|
6035
|
+
if (firstWordStartIndex === tag.plainTextBeginIndex) {
|
6036
|
+
start = firstWordStartIndex;
|
6037
|
+
}
|
6038
|
+
else {
|
6039
|
+
start = Math.max(firstWordStartIndex + 1, tag.plainTextBeginIndex);
|
6040
|
+
}
|
6041
|
+
const firstWordEndIndex = textInput.indexOf(' ', selectionStart);
|
6042
|
+
end = Math.max(firstWordEndIndex + 1, (_a = tag.plainTextEndIndex) !== null && _a !== void 0 ? _a : firstWordEndIndex + 1);
|
6043
|
+
if (selectionEnd !== undefined && tag.plainTextEndIndex !== undefined) {
|
6044
|
+
const lastWordEndIndex = textInput.indexOf(' ', selectionEnd);
|
6045
|
+
end = Math.max(lastWordEndIndex > -1 ? lastWordEndIndex : tag.plainTextEndIndex, selectionEnd);
|
6046
|
+
}
|
6047
|
+
return { start, end };
|
6033
6048
|
};
|
6034
|
-
|
6035
|
-
// Copyright (c) Microsoft Corporation.
|
6036
6049
|
/**
|
6037
|
-
*
|
6050
|
+
* Find a new the selection index.
|
6038
6051
|
*
|
6039
|
-
* @
|
6052
|
+
* @private
|
6053
|
+
* @param props - Props for finding new selection index for mention.
|
6054
|
+
* @returns New selection index if it is inside of a mention tag, otherwise the current selection.
|
6040
6055
|
*/
|
6041
|
-
const
|
6042
|
-
|
6043
|
-
const
|
6044
|
-
|
6045
|
-
|
6046
|
-
|
6047
|
-
|
6048
|
-
|
6049
|
-
|
6050
|
-
|
6051
|
-
|
6052
|
-
|
6053
|
-
|
6054
|
-
|
6055
|
-
|
6056
|
-
|
6057
|
-
|
6058
|
-
if (changedSelection === undefined) {
|
6059
|
-
setChangedSelection(false);
|
6056
|
+
const findNewSelectionIndexForMention = (props) => {
|
6057
|
+
var _a;
|
6058
|
+
const { tag, textValue, currentSelectionIndex, previousSelectionIndex } = props;
|
6059
|
+
// check if this is a mention tag and selection should be updated
|
6060
|
+
if (tag.tagType !== MSFT_MENTION_TAG ||
|
6061
|
+
tag.plainTextBeginIndex === undefined ||
|
6062
|
+
currentSelectionIndex === previousSelectionIndex ||
|
6063
|
+
tag.plainTextEndIndex === undefined) {
|
6064
|
+
return currentSelectionIndex;
|
6065
|
+
}
|
6066
|
+
let spaceIndex = 0;
|
6067
|
+
if (currentSelectionIndex <= previousSelectionIndex) {
|
6068
|
+
// the cursor is moved to the left, find the last index before the cursor
|
6069
|
+
spaceIndex = textValue.lastIndexOf(' ', currentSelectionIndex !== null && currentSelectionIndex !== void 0 ? currentSelectionIndex : 0);
|
6070
|
+
if (spaceIndex === -1) {
|
6071
|
+
// no space before the selection, use the beginning of the tag
|
6072
|
+
spaceIndex = tag.plainTextBeginIndex;
|
6060
6073
|
}
|
6061
|
-
|
6062
|
-
|
6074
|
+
}
|
6075
|
+
else {
|
6076
|
+
// the cursor is moved to the right, find the fist index after the cursor
|
6077
|
+
spaceIndex = textValue.indexOf(' ', currentSelectionIndex !== null && currentSelectionIndex !== void 0 ? currentSelectionIndex : 0);
|
6078
|
+
if (spaceIndex === -1) {
|
6079
|
+
// no space after the selection, use the end of the tag
|
6080
|
+
spaceIndex = (_a = tag.plainTextEndIndex) !== null && _a !== void 0 ? _a : tag.plainTextBeginIndex;
|
6063
6081
|
}
|
6064
|
-
}
|
6065
|
-
|
6066
|
-
|
6067
|
-
|
6068
|
-
|
6082
|
+
}
|
6083
|
+
spaceIndex = Math.max(tag.plainTextBeginIndex, spaceIndex);
|
6084
|
+
spaceIndex = Math.min(tag.plainTextEndIndex, spaceIndex);
|
6085
|
+
return spaceIndex;
|
6086
|
+
};
|
6087
|
+
/**
|
6088
|
+
* Handle mention tag edit and by word deleting
|
6089
|
+
*
|
6090
|
+
* @private
|
6091
|
+
* @param props - Props for mention update HTML function.
|
6092
|
+
* @returns Updated texts and indexes.
|
6093
|
+
*/
|
6094
|
+
const handleMentionTagUpdate = (props) => {
|
6095
|
+
const { htmlText, oldPlainText, change, tag, closeTagIdx, closeTagLength, plainTextEndIndex, startIndex, oldPlainTextEndIndex, mentionTagLength } = props;
|
6096
|
+
let processedChange = props.processedChange;
|
6097
|
+
let lastProcessedHTMLIndex = props.lastProcessedHTMLIndex;
|
6098
|
+
if (tag.tagType !== MSFT_MENTION_TAG || tag.plainTextBeginIndex === undefined) {
|
6099
|
+
// not a mention tag
|
6100
|
+
return {
|
6101
|
+
result: '',
|
6102
|
+
updatedChange: processedChange,
|
6103
|
+
htmlIndex: lastProcessedHTMLIndex,
|
6104
|
+
plainTextSelectionEndIndex: undefined
|
6069
6105
|
};
|
6070
|
-
}
|
6071
|
-
|
6072
|
-
|
6073
|
-
|
6074
|
-
|
6075
|
-
|
6076
|
-
|
6077
|
-
|
6078
|
-
|
6079
|
-
|
6080
|
-
|
6081
|
-
|
6082
|
-
|
6083
|
-
|
6106
|
+
}
|
6107
|
+
let result = '';
|
6108
|
+
let plainTextSelectionEndIndex;
|
6109
|
+
let rangeStart;
|
6110
|
+
let rangeEnd;
|
6111
|
+
// check if space symbol is handled in case if string looks like '<1 2 3>'
|
6112
|
+
let isSpaceLengthHandled = false;
|
6113
|
+
rangeStart = oldPlainText.lastIndexOf(' ', startIndex);
|
6114
|
+
if (rangeStart !== -1 && rangeStart !== undefined && rangeStart > tag.plainTextBeginIndex) {
|
6115
|
+
isSpaceLengthHandled = true;
|
6116
|
+
}
|
6117
|
+
rangeEnd = oldPlainText.indexOf(' ', oldPlainTextEndIndex);
|
6118
|
+
if (rangeEnd === -1 || rangeEnd === undefined) {
|
6119
|
+
// check if space symbol is not found
|
6120
|
+
rangeEnd = plainTextEndIndex;
|
6121
|
+
}
|
6122
|
+
else if (!isSpaceLengthHandled) {
|
6123
|
+
// +1 to include the space symbol
|
6124
|
+
rangeEnd += 1;
|
6125
|
+
}
|
6126
|
+
isSpaceLengthHandled = true;
|
6127
|
+
if (rangeStart === -1 || rangeStart === undefined || rangeStart < tag.plainTextBeginIndex) {
|
6128
|
+
// rangeStart should be at least equal to tag.plainTextBeginIndex
|
6129
|
+
rangeStart = tag.plainTextBeginIndex;
|
6130
|
+
}
|
6131
|
+
if (rangeEnd > plainTextEndIndex) {
|
6132
|
+
// rangeEnd should be at most equal to plainTextEndIndex
|
6133
|
+
rangeEnd = plainTextEndIndex;
|
6134
|
+
}
|
6135
|
+
if (rangeStart === tag.plainTextBeginIndex && rangeEnd === plainTextEndIndex) {
|
6136
|
+
// the whole tag should be removed
|
6137
|
+
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
|
6138
|
+
plainTextSelectionEndIndex = tag.plainTextBeginIndex + processedChange.length;
|
6139
|
+
processedChange = '';
|
6140
|
+
lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
|
6141
|
+
}
|
6142
|
+
else {
|
6143
|
+
// only part of the tag should be removed
|
6144
|
+
let startChangeDiff = 0;
|
6145
|
+
let endChangeDiff = 0;
|
6146
|
+
// need to check only rangeStart > tag.plainTextBeginIndex as when rangeStart === tag.plainTextBeginIndex startChangeDiff = 0 and mentionTagLength shouldn't be subtracted
|
6147
|
+
if (rangeStart > tag.plainTextBeginIndex) {
|
6148
|
+
startChangeDiff = rangeStart - tag.plainTextBeginIndex - mentionTagLength;
|
6084
6149
|
}
|
6085
|
-
|
6086
|
-
|
6150
|
+
endChangeDiff = rangeEnd - tag.plainTextBeginIndex - mentionTagLength;
|
6151
|
+
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff);
|
6152
|
+
if (startIndex < tag.plainTextBeginIndex) {
|
6153
|
+
// if the change is before the tag, the selection should start from startIndex (rangeStart will be equal to tag.plainTextBeginIndex)
|
6154
|
+
plainTextSelectionEndIndex = startIndex + change.length;
|
6087
6155
|
}
|
6088
6156
|
else {
|
6089
|
-
//
|
6090
|
-
|
6091
|
-
}
|
6092
|
-
setPosition(finalPosition);
|
6093
|
-
}, [location, target, targetPositionOffset]);
|
6094
|
-
const handleOnKeyDown = React.useCallback((e) => {
|
6095
|
-
switch (e.key) {
|
6096
|
-
case 'Escape':
|
6097
|
-
onDismiss && onDismiss();
|
6098
|
-
break;
|
6099
|
-
}
|
6100
|
-
}, [onDismiss]);
|
6101
|
-
const personaRenderer = React.useCallback((displayName) => {
|
6102
|
-
const displayNamePlaceholder = localeStrings.participantItem.displayNamePlaceholder;
|
6103
|
-
const avatarOptions = {
|
6104
|
-
text: (displayName === null || displayName === void 0 ? void 0 : displayName.trim()) || displayNamePlaceholder,
|
6105
|
-
size: react.PersonaSize.size24,
|
6106
|
-
initialsColor: theme.palette.neutralLight,
|
6107
|
-
initialsTextColor: theme.palette.neutralSecondary,
|
6108
|
-
showOverflowTooltip: false,
|
6109
|
-
showUnknownPersonaCoin: !(displayName === null || displayName === void 0 ? void 0 : displayName.trim()) || displayName === displayNamePlaceholder
|
6110
|
-
};
|
6111
|
-
return React__default['default'].createElement(react.Persona, Object.assign({}, avatarOptions));
|
6112
|
-
}, [localeStrings, theme]);
|
6113
|
-
const defaultOnRenderSuggestionItem = React.useCallback((suggestion, onSuggestionSelected, active) => {
|
6114
|
-
return (React__default['default'].createElement("div", { "data-is-focusable": true, "data-ui-id": ids.mentionSuggestionItem, key: suggestion.id, onClick: () => onSuggestionSelected(suggestion), onMouseEnter: () => setHoveredSuggestion(suggestion), onMouseLeave: () => setHoveredSuggestion(undefined), onKeyDown: (e) => {
|
6115
|
-
handleOnKeyDown(e);
|
6116
|
-
}, className: suggestionItemWrapperStyle(theme) },
|
6117
|
-
React__default['default'].createElement(react.Stack, { horizontal: true, className: suggestionItemStackStyle(theme, (hoveredSuggestion === null || hoveredSuggestion === void 0 ? void 0 : hoveredSuggestion.id) === suggestion.id, (changedSelection !== null && changedSelection !== void 0 ? changedSelection : false) && active) }, personaRenderer(suggestion.displayText))));
|
6118
|
-
}, [
|
6119
|
-
handleOnKeyDown,
|
6120
|
-
theme,
|
6121
|
-
/* @conditional-compile-remove(mention) */
|
6122
|
-
ids,
|
6123
|
-
hoveredSuggestion,
|
6124
|
-
changedSelection,
|
6125
|
-
personaRenderer
|
6126
|
-
]);
|
6127
|
-
const getHeaderTitle = React.useCallback(() => {
|
6128
|
-
if (title) {
|
6129
|
-
return title;
|
6157
|
+
// if the change is inside the tag, the selection should start with rangeStart
|
6158
|
+
plainTextSelectionEndIndex = rangeStart + processedChange.length;
|
6130
6159
|
}
|
6131
|
-
|
6132
|
-
|
6133
|
-
}
|
6134
|
-
return
|
6135
|
-
React__default['default'].createElement(react.Stack, { className: react.mergeStyles({
|
6136
|
-
maxHeight: 212,
|
6137
|
-
maxWidth: position.maxWidth
|
6138
|
-
}, mentionPopoverContainerStyle(theme), Object.assign(Object.assign({}, position), { position: 'absolute' })) },
|
6139
|
-
React__default['default'].createElement(react.Stack.Item, { styles: headerStyleThemed(theme), "aria-label": title }, getHeaderTitle()),
|
6140
|
-
React__default['default'].createElement(react.Stack
|
6141
|
-
/* @conditional-compile-remove(mention) */
|
6142
|
-
, { "data-ui-id": ids.mentionSuggestionList, className: suggestionListStyle }, suggestions.map((suggestion, index) => {
|
6143
|
-
const active = index === activeSuggestionIndex;
|
6144
|
-
return onRenderSuggestionItem
|
6145
|
-
? onRenderSuggestionItem(suggestion, onSuggestionSelected, active)
|
6146
|
-
: defaultOnRenderSuggestionItem(suggestion, onSuggestionSelected, active);
|
6147
|
-
})))));
|
6160
|
+
lastProcessedHTMLIndex = tag.openTagIndex + tag.openTagBody.length + endChangeDiff;
|
6161
|
+
// processed change should not be changed as it should be added after the tag
|
6162
|
+
}
|
6163
|
+
return { result, updatedChange: processedChange, htmlIndex: lastProcessedHTMLIndex, plainTextSelectionEndIndex };
|
6148
6164
|
};
|
6149
|
-
|
6150
|
-
|
6151
|
-
|
6152
|
-
|
6153
|
-
|
6154
|
-
|
6155
|
-
|
6156
|
-
|
6157
|
-
|
6158
|
-
|
6159
|
-
|
6165
|
+
/**
|
6166
|
+
* Get closing tag information if exists otherwise return information as for self closing tag
|
6167
|
+
*
|
6168
|
+
* @private
|
6169
|
+
* @param tag - Tag data.
|
6170
|
+
* @returns Closing tag information for the provided tag.
|
6171
|
+
*/
|
6172
|
+
const getTagClosingTagInfo = (tag) => {
|
6173
|
+
let plainTextEndIndex = 0;
|
6174
|
+
let closeTagIdx = 0;
|
6175
|
+
let closeTagLength = 0;
|
6176
|
+
if (tag.plainTextEndIndex !== undefined && tag.closingTagIndex !== undefined) {
|
6177
|
+
// close tag exists
|
6178
|
+
plainTextEndIndex = tag.plainTextEndIndex;
|
6179
|
+
closeTagIdx = tag.closingTagIndex;
|
6180
|
+
// tag.tagType.length + </>
|
6181
|
+
closeTagLength = tag.tagType.length + 3;
|
6182
|
+
}
|
6183
|
+
else if (tag.plainTextBeginIndex !== undefined) {
|
6184
|
+
// no close tag
|
6185
|
+
plainTextEndIndex = tag.plainTextBeginIndex;
|
6186
|
+
closeTagIdx = tag.openTagIndex + tag.openTagBody.length;
|
6187
|
+
closeTagLength = 0;
|
6188
|
+
}
|
6189
|
+
return { plainTextEndIndex, closeTagIdx, closeTagLength };
|
6160
6190
|
};
|
6161
|
-
/* @conditional-compile-remove(mention) */
|
6162
|
-
const DEFAULT_MENTION_TRIGGER = '@';
|
6163
|
-
/* @conditional-compile-remove(mention) */
|
6164
|
-
const MSFT_MENTION_TAG = 'msft-mention';
|
6165
6191
|
/**
|
6192
|
+
* Go through the text and update it with the changed text
|
6193
|
+
*
|
6166
6194
|
* @private
|
6195
|
+
* @param props - Props for update HTML function.
|
6196
|
+
* @returns Updated HTML and selection index if the selection index should be set.
|
6167
6197
|
*/
|
6168
|
-
const
|
6169
|
-
const {
|
6170
|
-
|
6171
|
-
|
6172
|
-
|
6173
|
-
|
6174
|
-
|
6175
|
-
|
6176
|
-
|
6177
|
-
//
|
6178
|
-
|
6179
|
-
|
6180
|
-
//
|
6181
|
-
|
6182
|
-
|
6183
|
-
|
6184
|
-
|
6185
|
-
|
6186
|
-
|
6187
|
-
|
6188
|
-
|
6189
|
-
|
6190
|
-
|
6191
|
-
const [selectionEndValue, setSelectionEndValue] = React.useState();
|
6192
|
-
/* @conditional-compile-remove(mention) */
|
6193
|
-
// Boolean value to check if onMouseDown event should be handled during select as selection range
|
6194
|
-
// for onMouseDown event is not updated yet and the selection range for mouse click/taps will be
|
6195
|
-
// updated in onSelect event if needed.
|
6196
|
-
const [shouldHandleOnMouseDownDuringSelect, setShouldHandleOnMouseDownDuringSelect] = React.useState(true);
|
6197
|
-
/* @conditional-compile-remove(mention) */
|
6198
|
-
// Point of start of touch/mouse selection
|
6199
|
-
const [interactionStartPoint, setInteractionStartPoint] = React.useState();
|
6200
|
-
/* @conditional-compile-remove(mention) */
|
6201
|
-
// Target selection from mouse movement
|
6202
|
-
const [targetSelection, setTargetSelection] = React.useState();
|
6203
|
-
/* @conditional-compile-remove(mention) */
|
6204
|
-
// Caret position in the text field
|
6205
|
-
const [caretPosition, setCaretPosition] = React.useState(undefined);
|
6206
|
-
/* @conditional-compile-remove(mention) */
|
6207
|
-
// Index of where the caret is in the text field
|
6208
|
-
const [caretIndex, setCaretIndex] = React.useState(undefined);
|
6209
|
-
/* @conditional-compile-remove(mention) */
|
6210
|
-
const localeStrings = useLocale$1().strings;
|
6211
|
-
/* @conditional-compile-remove(mention) */
|
6212
|
-
// Set mention suggestions
|
6213
|
-
const updateMentionSuggestions = React.useCallback((suggestions) => {
|
6214
|
-
setMentionSuggestions(suggestions);
|
6215
|
-
}, [setMentionSuggestions]);
|
6216
|
-
/* @conditional-compile-remove(mention) */
|
6217
|
-
// Parse the text and get the plain text version to display in the input box
|
6218
|
-
React.useEffect(() => {
|
6219
|
-
const trigger = (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) || DEFAULT_MENTION_TRIGGER;
|
6220
|
-
const parsedHTMLData = textToTagParser(textValue, trigger);
|
6221
|
-
setInputTextValue(parsedHTMLData.plainText);
|
6222
|
-
setTagsValue(parsedHTMLData.tags);
|
6223
|
-
updateMentionSuggestions([]);
|
6224
|
-
}, [textValue, mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger, updateMentionSuggestions]);
|
6225
|
-
const mergedRootStyle = react.mergeStyles(inputBoxWrapperStyle, styles === null || styles === void 0 ? void 0 : styles.root);
|
6226
|
-
const mergedInputFieldStyle = react.mergeStyles(inputBoxStyle, inputClassName, props.inlineChildren ? {} : inputBoxNewLineSpaceAffordance);
|
6227
|
-
/* @conditional-compile-remove(mention) */
|
6228
|
-
React.useEffect(() => {
|
6229
|
-
var _a;
|
6230
|
-
// effect for caret index update
|
6231
|
-
if (caretIndex === undefined || textFieldRef === undefined || (textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === undefined) {
|
6232
|
-
return;
|
6198
|
+
const updateHTML = (props) => {
|
6199
|
+
const { htmlText, oldPlainText, newPlainText, tags, startIndex, oldPlainTextEndIndex, change, mentionTrigger } = props;
|
6200
|
+
if (tags.length === 0 || (startIndex === 0 && oldPlainTextEndIndex === oldPlainText.length - 1)) {
|
6201
|
+
// no tags added yet or the whole text is changed
|
6202
|
+
return { updatedHTML: newPlainText, updatedSelectionIndex: undefined };
|
6203
|
+
}
|
6204
|
+
let result = '';
|
6205
|
+
let lastProcessedHTMLIndex = 0;
|
6206
|
+
// the value can be updated with empty string when the change covers more than 1 place (tag + before or after the tag)
|
6207
|
+
// in this case change won't be added as part of the tag
|
6208
|
+
// 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
|
6209
|
+
// 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
|
6210
|
+
// e.g.: change is on the beginning of the tag => change will be added before the tag
|
6211
|
+
// 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
|
6212
|
+
let processedChange = change;
|
6213
|
+
// end tag plain text index of the last processed tag
|
6214
|
+
let lastProcessedPlainTextTagEndIndex = 0;
|
6215
|
+
// as some tags/text can be removed fully, selection should be updated correctly
|
6216
|
+
let changeNewEndIndex;
|
6217
|
+
for (let i = 0; i < tags.length; i++) {
|
6218
|
+
const tag = tags[i];
|
6219
|
+
if (tag.plainTextBeginIndex === undefined) {
|
6220
|
+
continue;
|
6233
6221
|
}
|
6234
|
-
//
|
6235
|
-
|
6236
|
-
|
6237
|
-
|
6238
|
-
|
6239
|
-
|
6240
|
-
|
6241
|
-
|
6242
|
-
setSelectionEndValue(updatedCaretIndex);
|
6243
|
-
}, [caretIndex, inputTextValue.length, textFieldRef, setSelectionStartValue, setSelectionEndValue]);
|
6244
|
-
const mergedTextContainerStyle = react.mergeStyles(textContainerStyle, styles === null || styles === void 0 ? void 0 : styles.textFieldContainer);
|
6245
|
-
const mergedTextFieldStyle = react.concatStyleSets(textFieldStyle, {
|
6246
|
-
fieldGroup: styles === null || styles === void 0 ? void 0 : styles.textField,
|
6247
|
-
errorMessage: styles === null || styles === void 0 ? void 0 : styles.systemMessage,
|
6248
|
-
suffix: {
|
6249
|
-
backgroundColor: 'transparent',
|
6250
|
-
// Remove empty space in the suffix area when adding newline-style buttons
|
6251
|
-
display: props.inlineChildren ? 'flex' : 'contents',
|
6252
|
-
padding: '0 0.25rem'
|
6253
|
-
}
|
6254
|
-
});
|
6255
|
-
const mergedChildrenStyle = react.mergeStyles(props.inlineChildren ? {} : newLineButtonsContainerStyle);
|
6256
|
-
/* @conditional-compile-remove(mention) */
|
6257
|
-
const onSuggestionSelected = React.useCallback((suggestion) => {
|
6258
|
-
var _a, _b, _c;
|
6259
|
-
let selectionEnd = ((_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.selectionEnd) || -1;
|
6260
|
-
if (selectionEnd < 0) {
|
6261
|
-
selectionEnd = 0;
|
6262
|
-
}
|
6263
|
-
else if (selectionEnd > inputTextValue.length) {
|
6264
|
-
selectionEnd = inputTextValue.length;
|
6265
|
-
}
|
6266
|
-
const oldPlainText = inputTextValue;
|
6267
|
-
const mention = htmlStringForMentionSuggestion(suggestion, localeStrings);
|
6268
|
-
// update plain text with the mention html text
|
6269
|
-
const newPlainText = inputTextValue.substring(0, currentTriggerStartIndex) + mention + inputTextValue.substring(selectionEnd);
|
6270
|
-
const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : DEFAULT_MENTION_TRIGGER;
|
6271
|
-
// update html text with updated plain text
|
6272
|
-
const updatedContent = updateHTML({
|
6273
|
-
htmlText: textValue,
|
6274
|
-
oldPlainText,
|
6275
|
-
newPlainText,
|
6276
|
-
tags: tagsValue,
|
6277
|
-
startIndex: currentTriggerStartIndex,
|
6278
|
-
oldPlainTextEndIndex: selectionEnd,
|
6279
|
-
change: mention,
|
6280
|
-
mentionTrigger: triggerText
|
6281
|
-
});
|
6282
|
-
const displayName = getDisplayNameForMentionSuggestion(suggestion, localeStrings);
|
6283
|
-
const newCaretIndex = currentTriggerStartIndex + displayName.length + triggerText.length;
|
6284
|
-
// move the caret in the text field to the end of the mention plain text
|
6285
|
-
setCaretIndex(newCaretIndex);
|
6286
|
-
setSelectionEndValue(newCaretIndex);
|
6287
|
-
setSelectionStartValue(newCaretIndex);
|
6288
|
-
setCurrentTriggerStartIndex(-1);
|
6289
|
-
updateMentionSuggestions([]);
|
6290
|
-
// set focus back to text field
|
6291
|
-
(_c = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _c === void 0 ? void 0 : _c.focus();
|
6292
|
-
setActiveSuggestionIndex(undefined);
|
6293
|
-
onChange && onChange(undefined, updatedContent.updatedHTML);
|
6294
|
-
}, [
|
6295
|
-
textFieldRef,
|
6296
|
-
inputTextValue,
|
6297
|
-
currentTriggerStartIndex,
|
6298
|
-
mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger,
|
6299
|
-
onChange,
|
6300
|
-
textValue,
|
6301
|
-
tagsValue,
|
6302
|
-
/* @conditional-compile-remove(mention) */
|
6303
|
-
updateMentionSuggestions,
|
6304
|
-
/* @conditional-compile-remove(mention) */
|
6305
|
-
localeStrings
|
6306
|
-
]);
|
6307
|
-
const onTextFieldKeyDown = React.useCallback((ev) => {
|
6308
|
-
/* @conditional-compile-remove(mention) */
|
6309
|
-
// caretIndex should be set to undefined when the user is typing
|
6310
|
-
setCaretIndex(undefined);
|
6311
|
-
// shouldHandleOnMouseDownDuringSelect should be set to false after the last mouse down event.
|
6312
|
-
// it shouldn't be updated in onMouseUp
|
6313
|
-
// as onMouseUp can be triggered before or after onSelect event
|
6314
|
-
// because its order depends on mouse events not selection.
|
6315
|
-
/* @conditional-compile-remove(mention) */
|
6316
|
-
setShouldHandleOnMouseDownDuringSelect(false);
|
6317
|
-
if (isEnterKeyEventFromCompositionSession(ev)) {
|
6318
|
-
return;
|
6222
|
+
// all plain text indexes includes trigger length for the mention that shouldn't be included in
|
6223
|
+
// htmlText.substring because html strings don't include the trigger
|
6224
|
+
// mentionTagLength will be set only for mention tag, otherwise should be 0
|
6225
|
+
let mentionTagLength = 0;
|
6226
|
+
let isMentionTag = false;
|
6227
|
+
if (tag.tagType === MSFT_MENTION_TAG) {
|
6228
|
+
mentionTagLength = mentionTrigger.length;
|
6229
|
+
isMentionTag = true;
|
6319
6230
|
}
|
6320
|
-
|
6321
|
-
|
6322
|
-
|
6323
|
-
|
6324
|
-
|
6325
|
-
|
6326
|
-
|
6327
|
-
|
6328
|
-
|
6329
|
-
|
6330
|
-
|
6331
|
-
|
6332
|
-
|
6333
|
-
: Math.min(activeSuggestionIndex + 1, mentionSuggestions.length - 1);
|
6334
|
-
setActiveSuggestionIndex(newActiveIndex);
|
6231
|
+
if (startIndex <= tag.plainTextBeginIndex) {
|
6232
|
+
// change start is before the open tag
|
6233
|
+
// Math.max(lastProcessedPlainTextTagEndIndex, startIndex) is used as startIndex may not be in [[previous tag].plainTextEndIndex - tag.plainTextBeginIndex] range
|
6234
|
+
const startChangeDiff = tag.plainTextBeginIndex - Math.max(lastProcessedPlainTextTagEndIndex, startIndex);
|
6235
|
+
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex - startChangeDiff) + processedChange;
|
6236
|
+
processedChange = '';
|
6237
|
+
if (oldPlainTextEndIndex <= tag.plainTextBeginIndex) {
|
6238
|
+
// the whole change is before tag start
|
6239
|
+
// mentionTag length can be ignored here as the change is before the tag
|
6240
|
+
const endChangeDiff = tag.plainTextBeginIndex - oldPlainTextEndIndex;
|
6241
|
+
lastProcessedHTMLIndex = tag.openTagIndex - endChangeDiff;
|
6242
|
+
// the change is handled; exit
|
6243
|
+
break;
|
6335
6244
|
}
|
6336
|
-
else
|
6337
|
-
|
6245
|
+
else {
|
6246
|
+
// change continues in the tag
|
6247
|
+
lastProcessedHTMLIndex = tag.openTagIndex;
|
6248
|
+
// proceed to the next check
|
6338
6249
|
}
|
6339
6250
|
}
|
6340
|
-
|
6341
|
-
|
6342
|
-
//
|
6343
|
-
|
6344
|
-
|
6345
|
-
|
6346
|
-
|
6347
|
-
|
6348
|
-
|
6251
|
+
const closingTagInfo = getTagClosingTagInfo(tag);
|
6252
|
+
if (startIndex <= closingTagInfo.plainTextEndIndex) {
|
6253
|
+
// change started before the end tag
|
6254
|
+
if (startIndex <= tag.plainTextBeginIndex && oldPlainTextEndIndex === closingTagInfo.plainTextEndIndex) {
|
6255
|
+
// the change is a tag or starts before the tag
|
6256
|
+
// tag should be removed, no matter if there are sub-tags
|
6257
|
+
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
|
6258
|
+
processedChange = '';
|
6259
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
|
6260
|
+
// the change is handled; exit
|
6261
|
+
break;
|
6262
|
+
}
|
6263
|
+
else if (startIndex >= tag.plainTextBeginIndex && oldPlainTextEndIndex <= closingTagInfo.plainTextEndIndex) {
|
6264
|
+
// the change is between the tag
|
6265
|
+
if (isMentionTag) {
|
6266
|
+
if (change !== '') {
|
6267
|
+
if (startIndex !== tag.plainTextBeginIndex && startIndex !== closingTagInfo.plainTextEndIndex) {
|
6268
|
+
// mention tag should be deleted when user tries to edit it in the middle
|
6269
|
+
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
|
6270
|
+
changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
|
6271
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
|
6272
|
+
}
|
6273
|
+
else if (startIndex === tag.plainTextBeginIndex) {
|
6274
|
+
// non empty change at the beginning of the mention tag to be added before the mention tag
|
6275
|
+
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
|
6276
|
+
changeNewEndIndex = tag.plainTextBeginIndex + processedChange.length;
|
6277
|
+
lastProcessedHTMLIndex = tag.openTagIndex;
|
6278
|
+
}
|
6279
|
+
else if (startIndex === closingTagInfo.plainTextEndIndex) {
|
6280
|
+
// non empty change at the end of the mention tag to be added after the mention tag
|
6281
|
+
result +=
|
6282
|
+
htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength) +
|
6283
|
+
processedChange;
|
6284
|
+
changeNewEndIndex = closingTagInfo.plainTextEndIndex + processedChange.length;
|
6285
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
|
6286
|
+
}
|
6287
|
+
processedChange = '';
|
6288
|
+
}
|
6289
|
+
else {
|
6290
|
+
const updateMentionTagResult = handleMentionTagUpdate({
|
6291
|
+
htmlText,
|
6292
|
+
oldPlainText,
|
6293
|
+
lastProcessedHTMLIndex,
|
6294
|
+
processedChange,
|
6295
|
+
change,
|
6296
|
+
tag,
|
6297
|
+
closeTagIdx: closingTagInfo.closeTagIdx,
|
6298
|
+
closeTagLength: closingTagInfo.closeTagLength,
|
6299
|
+
plainTextEndIndex: closingTagInfo.plainTextEndIndex,
|
6300
|
+
startIndex,
|
6301
|
+
oldPlainTextEndIndex,
|
6302
|
+
mentionTagLength
|
6303
|
+
});
|
6304
|
+
result += updateMentionTagResult.result;
|
6305
|
+
changeNewEndIndex = updateMentionTagResult.plainTextSelectionEndIndex;
|
6306
|
+
processedChange = updateMentionTagResult.updatedChange;
|
6307
|
+
lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
|
6308
|
+
}
|
6309
|
+
}
|
6310
|
+
else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
|
6311
|
+
// with subtags
|
6312
|
+
const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
|
6313
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
|
6314
|
+
const updatedContent = updateHTML({
|
6315
|
+
htmlText: tag.content,
|
6316
|
+
oldPlainText,
|
6317
|
+
newPlainText,
|
6318
|
+
tags: tag.subTags,
|
6319
|
+
startIndex,
|
6320
|
+
oldPlainTextEndIndex,
|
6321
|
+
change: processedChange,
|
6322
|
+
mentionTrigger
|
6323
|
+
});
|
6324
|
+
result += stringBefore + updatedContent.updatedHTML;
|
6325
|
+
changeNewEndIndex = updatedContent.updatedSelectionIndex;
|
6326
|
+
}
|
6327
|
+
else {
|
6328
|
+
// no subtags
|
6329
|
+
const startChangeDiff = startIndex - tag.plainTextBeginIndex;
|
6330
|
+
result +=
|
6331
|
+
htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff) +
|
6332
|
+
processedChange;
|
6333
|
+
processedChange = '';
|
6334
|
+
if (oldPlainTextEndIndex < closingTagInfo.plainTextEndIndex) {
|
6335
|
+
const endChangeDiff = oldPlainTextEndIndex - tag.plainTextBeginIndex;
|
6336
|
+
lastProcessedHTMLIndex = tag.openTagIndex + tag.openTagBody.length + endChangeDiff;
|
6337
|
+
}
|
6338
|
+
else if (oldPlainTextEndIndex === closingTagInfo.plainTextEndIndex) {
|
6339
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
|
6340
|
+
}
|
6349
6341
|
}
|
6342
|
+
// the change is handled; exit
|
6343
|
+
break;
|
6350
6344
|
}
|
6351
|
-
|
6352
|
-
|
6353
|
-
|
6354
|
-
|
6355
|
-
|
6356
|
-
|
6357
|
-
|
6358
|
-
|
6359
|
-
|
6360
|
-
|
6361
|
-
|
6362
|
-
|
6363
|
-
|
6364
|
-
|
6365
|
-
|
6366
|
-
|
6367
|
-
|
6368
|
-
return (React__default['default'].createElement(react.Stack, { horizontal: true, className: mergedChildrenStyle }, children));
|
6369
|
-
};
|
6370
|
-
/* @conditional-compile-remove(mention) */
|
6371
|
-
const debouncedQueryUpdate = useDebounce.useDebouncedCallback((query) => __awaiter$w(void 0, void 0, void 0, function* () {
|
6372
|
-
var _a;
|
6373
|
-
const suggestions = (_a = (yield (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.onQueryUpdated(query)))) !== null && _a !== void 0 ? _a : [];
|
6374
|
-
if (suggestions.length === 0) {
|
6375
|
-
setActiveSuggestionIndex(undefined);
|
6376
|
-
}
|
6377
|
-
else if (activeSuggestionIndex === undefined) {
|
6378
|
-
// Set the active to the first, if it's not already set
|
6379
|
-
setActiveSuggestionIndex(0);
|
6380
|
-
}
|
6381
|
-
updateMentionSuggestions(suggestions);
|
6382
|
-
}), 500);
|
6383
|
-
/* @conditional-compile-remove(mention) */
|
6384
|
-
// Update selections index in mention to navigate by words
|
6385
|
-
const updateSelectionIndexesWithMentionIfNeeded = React.useCallback(({ event, inputTextValue, selectionEndValue, selectionStartValue, tagsValue }) => {
|
6386
|
-
var _a, _b, _c;
|
6387
|
-
let updatedStartIndex = event.currentTarget.selectionStart;
|
6388
|
-
let updatedEndIndex = event.currentTarget.selectionEnd;
|
6389
|
-
if (event.currentTarget.selectionStart === event.currentTarget.selectionEnd &&
|
6390
|
-
event.currentTarget.selectionStart !== null &&
|
6391
|
-
event.currentTarget.selectionStart !== -1) {
|
6392
|
-
// just a caret movement/usual typing or deleting
|
6393
|
-
const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
|
6394
|
-
// don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
|
6395
|
-
if (mentionTag !== undefined &&
|
6396
|
-
mentionTag.plainTextBeginIndex !== undefined &&
|
6397
|
-
event.currentTarget.selectionStart > mentionTag.plainTextBeginIndex &&
|
6398
|
-
event.currentTarget.selectionStart < ((_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex)) {
|
6399
|
-
// get updated selection index
|
6400
|
-
const newSelectionIndex = findNewSelectionIndexForMention({
|
6401
|
-
tag: mentionTag,
|
6402
|
-
textValue: inputTextValue,
|
6403
|
-
currentSelectionIndex: event.currentTarget.selectionStart,
|
6404
|
-
previousSelectionIndex: selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : inputTextValue.length
|
6405
|
-
});
|
6406
|
-
updatedStartIndex = newSelectionIndex;
|
6407
|
-
updatedEndIndex = newSelectionIndex;
|
6408
|
-
}
|
6409
|
-
}
|
6410
|
-
else if (event.currentTarget.selectionStart !== event.currentTarget.selectionEnd) {
|
6411
|
-
// Both e.currentTarget.selectionStart !== selectionStartValue and e.currentTarget.selectionEnd !== selectionEndValue can be true when a user selects a text by double click
|
6412
|
-
if (event.currentTarget.selectionStart !== null && event.currentTarget.selectionStart !== selectionStartValue) {
|
6413
|
-
// the selection start is changed
|
6414
|
-
const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
|
6415
|
-
// don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
|
6416
|
-
if (mentionTag !== undefined &&
|
6417
|
-
mentionTag.plainTextBeginIndex !== undefined &&
|
6418
|
-
event.currentTarget.selectionStart > mentionTag.plainTextBeginIndex &&
|
6419
|
-
event.currentTarget.selectionStart < ((_b = mentionTag.plainTextEndIndex) !== null && _b !== void 0 ? _b : mentionTag.plainTextBeginIndex)) {
|
6420
|
-
updatedStartIndex = findNewSelectionIndexForMention({
|
6421
|
-
tag: mentionTag,
|
6422
|
-
textValue: inputTextValue,
|
6423
|
-
currentSelectionIndex: event.currentTarget.selectionStart,
|
6424
|
-
previousSelectionIndex: selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : inputTextValue.length
|
6345
|
+
else if (startIndex > tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
|
6346
|
+
// the change started in the tag but finishes somewhere further
|
6347
|
+
const startChangeDiff = startIndex - tag.plainTextBeginIndex - mentionTagLength;
|
6348
|
+
if (isMentionTag) {
|
6349
|
+
const updateMentionTagResult = handleMentionTagUpdate({
|
6350
|
+
htmlText,
|
6351
|
+
oldPlainText,
|
6352
|
+
lastProcessedHTMLIndex,
|
6353
|
+
processedChange: '',
|
6354
|
+
change,
|
6355
|
+
tag,
|
6356
|
+
closeTagIdx: closingTagInfo.closeTagIdx,
|
6357
|
+
closeTagLength: closingTagInfo.closeTagLength,
|
6358
|
+
plainTextEndIndex: closingTagInfo.plainTextEndIndex,
|
6359
|
+
startIndex,
|
6360
|
+
oldPlainTextEndIndex,
|
6361
|
+
mentionTagLength
|
6425
6362
|
});
|
6363
|
+
result += updateMentionTagResult.result;
|
6364
|
+
lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
|
6365
|
+
// no need to handle plainTextSelectionEndIndex as the change will be added later
|
6426
6366
|
}
|
6427
|
-
|
6428
|
-
|
6429
|
-
|
6430
|
-
|
6431
|
-
|
6432
|
-
|
6433
|
-
|
6434
|
-
|
6435
|
-
|
6436
|
-
|
6437
|
-
|
6438
|
-
|
6439
|
-
|
6440
|
-
previousSelectionIndex: selectionEndValue !== null && selectionEndValue !== void 0 ? selectionEndValue : inputTextValue.length
|
6367
|
+
else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
|
6368
|
+
// with subtags
|
6369
|
+
const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
|
6370
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
|
6371
|
+
const updatedContent = updateHTML({
|
6372
|
+
htmlText: tag.content,
|
6373
|
+
oldPlainText,
|
6374
|
+
newPlainText,
|
6375
|
+
tags: tag.subTags,
|
6376
|
+
startIndex,
|
6377
|
+
oldPlainTextEndIndex,
|
6378
|
+
change: '',
|
6379
|
+
mentionTrigger
|
6441
6380
|
});
|
6381
|
+
result += stringBefore + updatedContent.updatedHTML;
|
6382
|
+
}
|
6383
|
+
else {
|
6384
|
+
// no subtags
|
6385
|
+
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff);
|
6386
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
|
6442
6387
|
}
|
6388
|
+
// proceed with the next calculations
|
6443
6389
|
}
|
6444
|
-
|
6445
|
-
|
6446
|
-
|
6447
|
-
|
6448
|
-
|
6449
|
-
|
6450
|
-
event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex, event.currentTarget.selectionDirection);
|
6451
|
-
}
|
6452
|
-
setSelectionStartValue(nullToUndefined(updatedStartIndex));
|
6453
|
-
setSelectionEndValue(nullToUndefined(updatedEndIndex));
|
6454
|
-
}, [setSelectionStartValue, setSelectionEndValue]);
|
6455
|
-
/* @conditional-compile-remove(mention) */
|
6456
|
-
const handleOnSelect = React.useCallback(({ event, inputTextValue, tags, shouldHandleOnMouseDownDuringSelect, selectionStartValue, selectionEndValue }) => {
|
6457
|
-
if (shouldHandleOnMouseDownDuringSelect) {
|
6458
|
-
if (targetSelection !== undefined) {
|
6459
|
-
setSelectionStartValue(targetSelection.start);
|
6460
|
-
setSelectionEndValue(targetSelection.end);
|
6461
|
-
event.currentTarget.setSelectionRange(targetSelection.start, undefinedToNull(targetSelection.end));
|
6462
|
-
setTargetSelection(undefined);
|
6390
|
+
else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
|
6391
|
+
// the change starts before the tag and finishes after it
|
6392
|
+
// tag should be removed, no matter if there are subtags
|
6393
|
+
// no need to save anything between lastProcessedHTMLIndex and closeTagIdx + closeTagLength
|
6394
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
|
6395
|
+
// proceed with the next calculations
|
6463
6396
|
}
|
6464
|
-
else if (
|
6465
|
-
//
|
6466
|
-
|
6467
|
-
|
6468
|
-
|
6469
|
-
|
6470
|
-
|
6471
|
-
|
6472
|
-
|
6473
|
-
|
6474
|
-
|
6397
|
+
else if (startIndex === tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
|
6398
|
+
// the change starts in the tag and finishes after it
|
6399
|
+
// tag should be removed, no matter if there are subtags
|
6400
|
+
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex);
|
6401
|
+
// processedChange shouldn't be updated as it will be added after the tag
|
6402
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
|
6403
|
+
// proceed with the next calculations
|
6404
|
+
}
|
6405
|
+
else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex < closingTagInfo.plainTextEndIndex) {
|
6406
|
+
// the change starts before the tag and ends in a tag
|
6407
|
+
if (isMentionTag) {
|
6408
|
+
// mention tag
|
6409
|
+
const updateMentionTagResult = handleMentionTagUpdate({
|
6410
|
+
htmlText,
|
6411
|
+
oldPlainText,
|
6412
|
+
lastProcessedHTMLIndex,
|
6413
|
+
processedChange: '',
|
6414
|
+
change,
|
6415
|
+
tag,
|
6416
|
+
closeTagIdx: closingTagInfo.closeTagIdx,
|
6417
|
+
closeTagLength: closingTagInfo.closeTagLength,
|
6418
|
+
plainTextEndIndex: closingTagInfo.plainTextEndIndex,
|
6419
|
+
startIndex,
|
6420
|
+
oldPlainTextEndIndex,
|
6421
|
+
mentionTagLength
|
6475
6422
|
});
|
6476
|
-
|
6477
|
-
|
6478
|
-
|
6479
|
-
|
6480
|
-
|
6481
|
-
|
6482
|
-
|
6483
|
-
|
6423
|
+
changeNewEndIndex = updateMentionTagResult.plainTextSelectionEndIndex;
|
6424
|
+
result += updateMentionTagResult.result;
|
6425
|
+
lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
|
6426
|
+
}
|
6427
|
+
else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
|
6428
|
+
// with subtags
|
6429
|
+
const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
|
6430
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
|
6431
|
+
const updatedContent = updateHTML({
|
6432
|
+
htmlText: tag.content,
|
6433
|
+
oldPlainText,
|
6434
|
+
newPlainText,
|
6435
|
+
tags: tag.subTags,
|
6436
|
+
startIndex,
|
6437
|
+
oldPlainTextEndIndex,
|
6438
|
+
change: processedChange,
|
6439
|
+
mentionTrigger
|
6440
|
+
});
|
6441
|
+
processedChange = '';
|
6442
|
+
result += stringBefore + updatedContent.updatedHTML;
|
6484
6443
|
}
|
6485
6444
|
else {
|
6486
|
-
|
6487
|
-
|
6445
|
+
// no subtags
|
6446
|
+
result +=
|
6447
|
+
htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length) + processedChange;
|
6448
|
+
processedChange = '';
|
6449
|
+
// oldPlainTextEndIndex already includes mentionTag length
|
6450
|
+
const endChangeDiff = closingTagInfo.plainTextEndIndex - oldPlainTextEndIndex;
|
6451
|
+
// as change may be before the end of the tag, we need to add the rest of the tag
|
6452
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx - endChangeDiff;
|
6488
6453
|
}
|
6454
|
+
// the change is handled; exit
|
6455
|
+
break;
|
6489
6456
|
}
|
6457
|
+
lastProcessedPlainTextTagEndIndex = closingTagInfo.plainTextEndIndex;
|
6490
6458
|
}
|
6491
|
-
|
6492
|
-
//
|
6493
|
-
|
6494
|
-
|
6495
|
-
|
6496
|
-
|
6497
|
-
|
6498
|
-
|
6499
|
-
}
|
6500
|
-
|
6501
|
-
|
6502
|
-
|
6503
|
-
|
6504
|
-
|
6505
|
-
|
6506
|
-
|
6507
|
-
|
6508
|
-
|
6509
|
-
|
6510
|
-
]);
|
6511
|
-
/* @conditional-compile-remove(mention) */
|
6512
|
-
const handleOnChange = React.useCallback(({ currentSelectionEnd, currentSelectionStart, currentTriggerStartIndex, event, htmlTextValue, inputTextValue, previousSelectionEnd, previousSelectionStart, tagsValue, updatedValue }) => __awaiter$w(void 0, void 0, void 0, function* () {
|
6513
|
-
var _b;
|
6514
|
-
debouncedQueryUpdate.cancel();
|
6515
|
-
if (event.currentTarget === null) {
|
6516
|
-
return;
|
6459
|
+
if (i === tags.length - 1 && oldPlainTextEndIndex >= closingTagInfo.plainTextEndIndex) {
|
6460
|
+
// the last tag should handle the end of the change if needed
|
6461
|
+
// oldPlainTextEndIndex already includes mentionTag length
|
6462
|
+
const endChangeDiff = oldPlainTextEndIndex - closingTagInfo.plainTextEndIndex;
|
6463
|
+
if (startIndex >= closingTagInfo.plainTextEndIndex) {
|
6464
|
+
const startChangeDiff = startIndex - closingTagInfo.plainTextEndIndex;
|
6465
|
+
result +=
|
6466
|
+
htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength + startChangeDiff) + processedChange;
|
6467
|
+
}
|
6468
|
+
else {
|
6469
|
+
result +=
|
6470
|
+
htmlText.substring(lastProcessedHTMLIndex, closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength) +
|
6471
|
+
processedChange;
|
6472
|
+
}
|
6473
|
+
processedChange = '';
|
6474
|
+
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength + endChangeDiff;
|
6475
|
+
// the change is handled; exit
|
6476
|
+
// break is not required here as this is the last element but added for consistency
|
6477
|
+
break;
|
6517
6478
|
}
|
6518
|
-
|
6519
|
-
|
6520
|
-
|
6521
|
-
|
6522
|
-
|
6523
|
-
|
6524
|
-
|
6525
|
-
|
6526
|
-
|
6527
|
-
|
6528
|
-
|
6529
|
-
|
6530
|
-
|
6531
|
-
|
6532
|
-
|
6533
|
-
|
6534
|
-
|
6535
|
-
|
6536
|
-
|
6537
|
-
|
6538
|
-
|
6539
|
-
|
6540
|
-
|
6541
|
-
|
6542
|
-
|
6543
|
-
|
6544
|
-
|
6545
|
-
//
|
6546
|
-
if (
|
6547
|
-
//
|
6548
|
-
|
6549
|
-
|
6550
|
-
|
6551
|
-
|
6552
|
-
|
6553
|
-
|
6554
|
-
|
6555
|
-
|
6556
|
-
if (
|
6557
|
-
//
|
6558
|
-
|
6559
|
-
setCurrentTriggerStartIndex(tagIndex);
|
6560
|
-
}
|
6561
|
-
else if (wordAtSelection === triggerText) {
|
6562
|
-
// start of the mention
|
6563
|
-
tagIndex = currentSelectionEndValue - triggerText.length;
|
6564
|
-
if (tagIndex < 0) {
|
6565
|
-
tagIndex = 0;
|
6566
|
-
}
|
6567
|
-
setCurrentTriggerStartIndex(tagIndex);
|
6568
|
-
}
|
6569
|
-
if (tagIndex === -1) {
|
6570
|
-
updateMentionSuggestions([]);
|
6571
|
-
}
|
6572
|
-
else {
|
6573
|
-
// In the middle of a @mention lookup
|
6574
|
-
if (tagIndex > -1) {
|
6575
|
-
const query = wordAtSelection.substring(triggerText.length, wordAtSelection.length);
|
6576
|
-
if (query !== undefined) {
|
6577
|
-
yield debouncedQueryUpdate(query);
|
6578
|
-
}
|
6579
|
-
}
|
6479
|
+
}
|
6480
|
+
if (lastProcessedHTMLIndex < htmlText.length) {
|
6481
|
+
// add the rest of the html string
|
6482
|
+
result += htmlText.substring(lastProcessedHTMLIndex);
|
6483
|
+
}
|
6484
|
+
return { updatedHTML: result, updatedSelectionIndex: changeNewEndIndex };
|
6485
|
+
};
|
6486
|
+
/**
|
6487
|
+
* Given the oldText and newText, find the start index, old end index and new end index for the changes
|
6488
|
+
*
|
6489
|
+
* @private
|
6490
|
+
* @param props - Props for finding stings diff indexes function.
|
6491
|
+
* @returns Indexes for change start and ends in new and old texts. The old and new end indexes are exclusive.
|
6492
|
+
*/
|
6493
|
+
const findStringsDiffIndexes = (props) => {
|
6494
|
+
const { oldText, newText, previousSelectionStart, previousSelectionEnd, currentSelectionStart, currentSelectionEnd } = props;
|
6495
|
+
const newTextLength = newText.length;
|
6496
|
+
const oldTextLength = oldText.length;
|
6497
|
+
// let changeStart = 0;
|
6498
|
+
let newChangeEnd = newTextLength;
|
6499
|
+
let oldChangeEnd = oldTextLength;
|
6500
|
+
const previousSelectionStartValue = previousSelectionStart > -1 ? previousSelectionStart : oldTextLength;
|
6501
|
+
const previousSelectionEndValue = previousSelectionEnd > -1 ? previousSelectionEnd : oldTextLength;
|
6502
|
+
const currentSelectionStartValue = currentSelectionStart > -1 ? currentSelectionStart : newTextLength;
|
6503
|
+
const currentSelectionEndValue = currentSelectionEnd > -1 ? currentSelectionEnd : newTextLength;
|
6504
|
+
const changeStart = Math.min(previousSelectionStartValue, previousSelectionEndValue, currentSelectionStartValue, currentSelectionEndValue, newTextLength, oldTextLength);
|
6505
|
+
if (oldTextLength < newTextLength) {
|
6506
|
+
//insert or replacement
|
6507
|
+
if (oldTextLength === changeStart) {
|
6508
|
+
// when change was at the end of string
|
6509
|
+
// change is found
|
6510
|
+
newChangeEnd = newTextLength;
|
6511
|
+
oldChangeEnd = oldTextLength;
|
6512
|
+
}
|
6513
|
+
else {
|
6514
|
+
for (let i = 1; i < newTextLength && oldTextLength - i >= changeStart; i++) {
|
6515
|
+
newChangeEnd = newTextLength - i - 1;
|
6516
|
+
oldChangeEnd = oldTextLength - i - 1;
|
6517
|
+
if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
|
6518
|
+
// change is found
|
6519
|
+
break;
|
6580
6520
|
}
|
6581
6521
|
}
|
6522
|
+
// make indexes exclusive
|
6523
|
+
newChangeEnd += 1;
|
6524
|
+
oldChangeEnd += 1;
|
6582
6525
|
}
|
6583
|
-
|
6584
|
-
|
6585
|
-
|
6586
|
-
|
6526
|
+
}
|
6527
|
+
else if (oldTextLength > newTextLength) {
|
6528
|
+
//deletion or replacement
|
6529
|
+
if (newTextLength === changeStart) {
|
6530
|
+
// when change was at the end of string
|
6531
|
+
// change is found
|
6532
|
+
newChangeEnd = newTextLength;
|
6533
|
+
oldChangeEnd = oldTextLength;
|
6587
6534
|
}
|
6588
6535
|
else {
|
6589
|
-
|
6590
|
-
|
6591
|
-
|
6592
|
-
oldText
|
6593
|
-
|
6594
|
-
|
6595
|
-
previousSelectionEnd: previousSelectionEndValue,
|
6596
|
-
currentSelectionStart: currentSelectionStartValue,
|
6597
|
-
currentSelectionEnd: currentSelectionEndValue
|
6598
|
-
});
|
6599
|
-
const change = newValue.substring(changeStart, newChangeEnd);
|
6600
|
-
// get updated html string
|
6601
|
-
const updatedContent = updateHTML({
|
6602
|
-
htmlText: htmlTextValue,
|
6603
|
-
oldPlainText: inputTextValue,
|
6604
|
-
newPlainText: newValue,
|
6605
|
-
tags: tagsValue,
|
6606
|
-
startIndex: changeStart,
|
6607
|
-
oldPlainTextEndIndex: oldChangeEnd,
|
6608
|
-
change,
|
6609
|
-
mentionTrigger: triggerText
|
6610
|
-
});
|
6611
|
-
result = updatedContent.updatedHTML;
|
6612
|
-
// update caret index if needed
|
6613
|
-
if (updatedContent.updatedSelectionIndex !== undefined) {
|
6614
|
-
setCaretIndex(updatedContent.updatedSelectionIndex);
|
6615
|
-
setSelectionEndValue(updatedContent.updatedSelectionIndex);
|
6616
|
-
setSelectionStartValue(updatedContent.updatedSelectionIndex);
|
6617
|
-
}
|
6618
|
-
}
|
6619
|
-
onChange && onChange(event, result);
|
6620
|
-
}), [onChange, mentionLookupOptions, setCaretIndex, setCaretPosition, updateMentionSuggestions, debouncedQueryUpdate]);
|
6621
|
-
const getInputFieldTextValue = () => {
|
6622
|
-
/* @conditional-compile-remove(mention) */
|
6623
|
-
return inputTextValue;
|
6624
|
-
};
|
6625
|
-
/* @conditional-compile-remove(mention) */
|
6626
|
-
// Adjust the selection range based on a mouse / touch interaction
|
6627
|
-
const handleOnMove = React.useCallback((event) => {
|
6628
|
-
var _a;
|
6629
|
-
let targetStart = event.currentTarget.selectionStart;
|
6630
|
-
let targetEnd = event.currentTarget.selectionEnd;
|
6631
|
-
// Should we do anything?
|
6632
|
-
if (interactionStartPoint !== undefined &&
|
6633
|
-
// And did selection change?
|
6634
|
-
targetStart !== null &&
|
6635
|
-
(targetStart !== (targetSelection === null || targetSelection === void 0 ? void 0 : targetSelection.start) || targetEnd !== (targetSelection === null || targetSelection === void 0 ? void 0 : targetSelection.end))) {
|
6636
|
-
const direction = event.clientX > interactionStartPoint.x ? 'forward' : 'backward';
|
6637
|
-
const mentionTag = findMentionTagForSelection(tagsValue, direction === 'backward'
|
6638
|
-
? event.currentTarget.selectionStart
|
6639
|
-
: (_a = event.currentTarget.selectionEnd) !== null && _a !== void 0 ? _a : event.currentTarget.selectionStart);
|
6640
|
-
let updateCurrentTarget = false;
|
6641
|
-
if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
|
6642
|
-
targetStart = Math.min(mentionTag.plainTextBeginIndex, targetStart);
|
6643
|
-
if (mentionTag.plainTextEndIndex !== undefined && targetEnd !== null) {
|
6644
|
-
targetEnd = Math.max(mentionTag.plainTextEndIndex, targetEnd);
|
6536
|
+
for (let i = 1; i < oldTextLength && newTextLength - i >= changeStart; i++) {
|
6537
|
+
newChangeEnd = newTextLength - i - 1;
|
6538
|
+
oldChangeEnd = oldTextLength - i - 1;
|
6539
|
+
if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
|
6540
|
+
// change is found
|
6541
|
+
break;
|
6645
6542
|
}
|
6646
|
-
updateCurrentTarget = true;
|
6647
|
-
setShouldHandleOnMouseDownDuringSelect(false);
|
6648
6543
|
}
|
6649
|
-
//
|
6650
|
-
|
6651
|
-
|
6652
|
-
|
6653
|
-
|
6544
|
+
// make indexes exclusive
|
6545
|
+
newChangeEnd += 1;
|
6546
|
+
oldChangeEnd += 1;
|
6547
|
+
}
|
6548
|
+
}
|
6549
|
+
else {
|
6550
|
+
// replacement
|
6551
|
+
for (let i = 1; i < oldTextLength && oldTextLength - i >= changeStart; i++) {
|
6552
|
+
newChangeEnd = newTextLength - i - 1;
|
6553
|
+
oldChangeEnd = oldTextLength - i - 1;
|
6554
|
+
if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
|
6555
|
+
// change is found
|
6556
|
+
break;
|
6654
6557
|
}
|
6655
6558
|
}
|
6656
|
-
|
6657
|
-
|
6658
|
-
|
6659
|
-
if (activeSuggestionIndex === undefined) {
|
6660
|
-
return undefined;
|
6559
|
+
// make indexes exclusive if they aren't equal to the length of the string
|
6560
|
+
if (newChangeEnd !== newText.length) {
|
6561
|
+
newChangeEnd += 1;
|
6661
6562
|
}
|
6662
|
-
|
6663
|
-
|
6664
|
-
|
6665
|
-
|
6666
|
-
|
6667
|
-
return (React__default['default'].createElement(react.Stack, { className: mergedRootStyle },
|
6668
|
-
React__default['default'].createElement("div", { className: mergedTextContainerStyle },
|
6669
|
-
/* @conditional-compile-remove(mention) */ mentionSuggestions.length > 0 && (React__default['default'].createElement(_MentionPopover, { suggestions: mentionSuggestions, activeSuggestionIndex: activeSuggestionIndex, target: inputBoxRef, targetPositionOffset: caretPosition, onRenderSuggestionItem: mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.onRenderSuggestionItem, onSuggestionSelected: onSuggestionSelected, onDismiss: () => {
|
6670
|
-
updateMentionSuggestions([]);
|
6671
|
-
} })),
|
6672
|
-
/* @conditional-compile-remove(mention) */ announcerText !== undefined && (React__default['default'].createElement(Announcer$1, { announcementString: announcerText, ariaLive: 'polite' })),
|
6673
|
-
React__default['default'].createElement(react.TextField, { autoFocus: props.autoFocus === 'sendBoxTextField', "data-ui-id": dataUiId, multiline: true, autoAdjustHeight: true, multiple: false, resizable: false, componentRef: textFieldRef, id: id, inputClassName: mergedInputFieldStyle, placeholder: placeholderText, value: getInputFieldTextValue(), onChange: (e, newValue) => {
|
6674
|
-
// Remove when switching to react 17+, currently needed because of https://legacy.reactjs.org/docs/legacy-event-pooling.html
|
6675
|
-
/* @conditional-compile-remove(mention) */
|
6676
|
-
// Prevents React from resetting event's properties
|
6677
|
-
e.persist();
|
6678
|
-
/* @conditional-compile-remove(mention) */
|
6679
|
-
setInputTextValue(newValue !== null && newValue !== void 0 ? newValue : '');
|
6680
|
-
/* @conditional-compile-remove(mention) */
|
6681
|
-
handleOnChange({
|
6682
|
-
event: e,
|
6683
|
-
tagsValue,
|
6684
|
-
htmlTextValue: textValue,
|
6685
|
-
inputTextValue,
|
6686
|
-
currentTriggerStartIndex,
|
6687
|
-
previousSelectionStart: nullToUndefined(selectionStartValue),
|
6688
|
-
previousSelectionEnd: nullToUndefined(selectionEndValue),
|
6689
|
-
currentSelectionStart: nullToUndefined(e.currentTarget.selectionStart),
|
6690
|
-
currentSelectionEnd: nullToUndefined(e.currentTarget.selectionEnd),
|
6691
|
-
updatedValue: newValue
|
6692
|
-
});
|
6693
|
-
/* @conditional-compile-remove(mention) */
|
6694
|
-
return;
|
6695
|
-
},
|
6696
|
-
/* @conditional-compile-remove(mention) */
|
6697
|
-
onSelect: (e) => {
|
6698
|
-
// update selection if needed
|
6699
|
-
if (caretIndex !== undefined) {
|
6700
|
-
setCaretIndex(undefined);
|
6701
|
-
// sometimes setting selectionRage in effect for updating caretIndex doesn't work as expected and onSelect should handle this case
|
6702
|
-
if (caretIndex !== e.currentTarget.selectionStart || caretIndex !== e.currentTarget.selectionEnd) {
|
6703
|
-
e.currentTarget.setSelectionRange(caretIndex, caretIndex);
|
6704
|
-
}
|
6705
|
-
return;
|
6706
|
-
}
|
6707
|
-
handleOnSelect({
|
6708
|
-
event: e,
|
6709
|
-
inputTextValue,
|
6710
|
-
shouldHandleOnMouseDownDuringSelect,
|
6711
|
-
selectionEndValue,
|
6712
|
-
selectionStartValue,
|
6713
|
-
tags: tagsValue
|
6714
|
-
});
|
6715
|
-
},
|
6716
|
-
/* @conditional-compile-remove(mention) */
|
6717
|
-
onMouseDown: (e) => {
|
6718
|
-
setInteractionStartPoint({ x: e.clientX, y: e.clientY });
|
6719
|
-
// as events order is onMouseDown -> onMouseMove -> onMouseUp -> onSelect -> onClick
|
6720
|
-
// onClick and onMouseDown can't handle clicking on mention event because
|
6721
|
-
// onMouseDown doesn't have correct selectionRange yet and
|
6722
|
-
// onClick already has wrong range as it's called after onSelect that updates the selection range
|
6723
|
-
// so we need to handle onMouseDown to prevent onSelect default behavior
|
6724
|
-
setShouldHandleOnMouseDownDuringSelect(true);
|
6725
|
-
},
|
6726
|
-
/* @conditional-compile-remove(mention) */
|
6727
|
-
onMouseMove: handleOnMove,
|
6728
|
-
/* @conditional-compile-remove(mention) */
|
6729
|
-
onMouseUp: () => {
|
6730
|
-
setInteractionStartPoint(undefined);
|
6731
|
-
},
|
6732
|
-
/* @conditional-compile-remove(mention) */
|
6733
|
-
onTouchStart: (e) => {
|
6734
|
-
setInteractionStartPoint({
|
6735
|
-
x: e.targetTouches.item(0).clientX,
|
6736
|
-
y: e.targetTouches.item(0).clientY
|
6737
|
-
});
|
6738
|
-
// see onMouseDown for more details
|
6739
|
-
setShouldHandleOnMouseDownDuringSelect(true);
|
6740
|
-
},
|
6741
|
-
/* @conditional-compile-remove(mention) */
|
6742
|
-
onTouchMove: handleOnMove,
|
6743
|
-
/* @conditional-compile-remove(mention) */
|
6744
|
-
onTouchEnd: () => {
|
6745
|
-
setInteractionStartPoint(undefined);
|
6746
|
-
},
|
6747
|
-
/* @conditional-compile-remove(mention) */
|
6748
|
-
onBlur: () => {
|
6749
|
-
// setup all flags to default values when text field loses focus
|
6750
|
-
setShouldHandleOnMouseDownDuringSelect(false);
|
6751
|
-
setCaretIndex(undefined);
|
6752
|
-
setSelectionStartValue(undefined);
|
6753
|
-
setSelectionEndValue(undefined);
|
6754
|
-
// Dismiss the suggestions on blur, after enough time to select by mouse if needed
|
6755
|
-
setTimeout(() => {
|
6756
|
-
setMentionSuggestions([]);
|
6757
|
-
}, 200);
|
6758
|
-
}, autoComplete: "off", onKeyDown: onTextFieldKeyDown, styles: mergedTextFieldStyle, disabled: disabled, errorMessage: errorMessage, onRenderSuffix: onRenderChildren, elementRef: inputBoxRef }))));
|
6563
|
+
if (oldChangeEnd !== oldText.length) {
|
6564
|
+
oldChangeEnd += 1;
|
6565
|
+
}
|
6566
|
+
}
|
6567
|
+
return { changeStart, oldChangeEnd, newChangeEnd };
|
6759
6568
|
};
|
6760
6569
|
/**
|
6570
|
+
* Get the html string for the mention suggestion.
|
6571
|
+
*
|
6761
6572
|
* @private
|
6573
|
+
* @param suggestion - The mention suggestion.
|
6574
|
+
* @param localeStrings - The locale strings.
|
6575
|
+
* @returns The html string for the mention suggestion.
|
6762
6576
|
*/
|
6763
|
-
const
|
6764
|
-
const
|
6765
|
-
const
|
6766
|
-
const
|
6767
|
-
|
6768
|
-
const calloutStyle = { root: { padding: 0 }, calloutMain: { padding: '0.5rem' } };
|
6769
|
-
// Place callout with no gap between it and the button.
|
6770
|
-
const calloutProps = {
|
6771
|
-
gapSpace: 0,
|
6772
|
-
styles: calloutStyle,
|
6773
|
-
backgroundColor: isDarkThemed(theme) ? theme.palette.neutralLighter : ''
|
6774
|
-
};
|
6775
|
-
return (React__default['default'].createElement(react.TooltipHost, { hostClassName: inputButtonTooltipStyle, content: tooltipContent, calloutProps: Object.assign({}, calloutProps) },
|
6776
|
-
React__default['default'].createElement(react.IconButton, { className: mergedButtonStyle, ariaLabel: ariaLabel, onClick: onClick, id: id, onMouseEnter: () => {
|
6777
|
-
setIsHover(true);
|
6778
|
-
}, onMouseLeave: () => {
|
6779
|
-
setIsHover(false);
|
6780
|
-
},
|
6781
|
-
// VoiceOver fix: Avoid icon from stealing focus when IconButton is double-tapped to send message by wrapping with Stack with pointerEvents style to none
|
6782
|
-
onRenderIcon: () => React__default['default'].createElement(react.Stack, { className: iconWrapperStyle$1 }, onRenderIcon(isHover)) })));
|
6577
|
+
const htmlStringForMentionSuggestion = (suggestion, localeStrings) => {
|
6578
|
+
const idHTML = ' id ="' + suggestion.id + '"';
|
6579
|
+
const displayTextHTML = ' displayText ="' + suggestion.displayText + '"';
|
6580
|
+
const displayText = getDisplayNameForMentionSuggestion(suggestion, localeStrings);
|
6581
|
+
return '<' + MSFT_MENTION_TAG + idHTML + displayTextHTML + '>' + displayText + '</' + MSFT_MENTION_TAG + '>';
|
6783
6582
|
};
|
6784
|
-
/* @conditional-compile-remove(mention) */
|
6785
6583
|
/**
|
6786
|
-
* Get
|
6584
|
+
* Get display name for the mention suggestion.
|
6787
6585
|
*
|
6788
6586
|
* @private
|
6789
|
-
*
|
6790
|
-
* @
|
6587
|
+
*
|
6588
|
+
* @param suggestion - The mention suggestion.
|
6589
|
+
* @param localeStrings - The locale strings.
|
6590
|
+
* @returns The display name for the mention suggestion or display name placeholder if display name is empty.
|
6791
6591
|
*/
|
6792
|
-
const
|
6793
|
-
const
|
6794
|
-
|
6795
|
-
updatedValue = Math.max(min, updatedValue);
|
6796
|
-
updatedValue = Math.min(updatedValue, max);
|
6797
|
-
return updatedValue;
|
6592
|
+
const getDisplayNameForMentionSuggestion = (suggestion, localeStrings) => {
|
6593
|
+
const displayNamePlaceholder = localeStrings.participantItem.displayNamePlaceholder;
|
6594
|
+
return suggestion.displayText !== '' ? suggestion.displayText : displayNamePlaceholder !== null && displayNamePlaceholder !== void 0 ? displayNamePlaceholder : '';
|
6798
6595
|
};
|
6799
|
-
/* @conditional-compile-remove(mention) */
|
6800
6596
|
/**
|
6801
|
-
*
|
6802
|
-
*
|
6597
|
+
* Parse the text and return the tags and the plain text in one go
|
6803
6598
|
* @private
|
6804
|
-
* @param
|
6805
|
-
* @param
|
6806
|
-
*
|
6599
|
+
* @param text - The text to parse for HTML tags
|
6600
|
+
* @param trigger The trigger to show for the mention tag in plain text
|
6601
|
+
*
|
6602
|
+
* @returns An array of tags and the plain text representation
|
6807
6603
|
*/
|
6808
|
-
const
|
6809
|
-
|
6810
|
-
tags
|
6811
|
-
|
6812
|
-
|
6813
|
-
|
6814
|
-
|
6604
|
+
const textToTagParser = (text, trigger) => {
|
6605
|
+
var _a, _b;
|
6606
|
+
const tags = []; // Tags passed back to the caller
|
6607
|
+
const tagParseStack = []; // Local stack to use while parsing
|
6608
|
+
let plainTextRepresentation = '';
|
6609
|
+
let parseIndex = 0;
|
6610
|
+
while (parseIndex < text.length) {
|
6611
|
+
const foundHtmlTag = findNextHtmlTag(text, parseIndex);
|
6612
|
+
if (!foundHtmlTag) {
|
6613
|
+
if (parseIndex !== 0) {
|
6614
|
+
// Add the remaining text to the plain text representation
|
6615
|
+
plainTextRepresentation += text.substring(parseIndex);
|
6616
|
+
}
|
6617
|
+
else {
|
6618
|
+
plainTextRepresentation = text;
|
6619
|
+
}
|
6620
|
+
break;
|
6815
6621
|
}
|
6816
|
-
|
6817
|
-
|
6818
|
-
|
6819
|
-
|
6820
|
-
|
6821
|
-
|
6822
|
-
|
6823
|
-
|
6824
|
-
|
6622
|
+
if (foundHtmlTag.type === 'open' || foundHtmlTag.type === 'self-closing') {
|
6623
|
+
const nextTag = parseOpenTag(foundHtmlTag.content, foundHtmlTag.startIdx);
|
6624
|
+
// Add the plain text between the last tag and this one found
|
6625
|
+
plainTextRepresentation += text.substring(parseIndex, foundHtmlTag.startIdx);
|
6626
|
+
nextTag.plainTextBeginIndex = plainTextRepresentation.length;
|
6627
|
+
if (foundHtmlTag.type === 'open') {
|
6628
|
+
tagParseStack.push(nextTag);
|
6629
|
+
}
|
6630
|
+
else {
|
6631
|
+
nextTag.content = '';
|
6632
|
+
nextTag.plainTextBeginIndex = plainTextRepresentation.length;
|
6633
|
+
nextTag.plainTextEndIndex = plainTextRepresentation.length;
|
6634
|
+
addTag(nextTag, tagParseStack, tags);
|
6635
|
+
}
|
6636
|
+
}
|
6637
|
+
if (foundHtmlTag.type === 'close') {
|
6638
|
+
const currentOpenTag = tagParseStack.pop();
|
6639
|
+
const closeTagType = foundHtmlTag.content.substring(2, foundHtmlTag.content.length - 1).toLowerCase();
|
6640
|
+
if (currentOpenTag && currentOpenTag.tagType === closeTagType) {
|
6641
|
+
// Tag startIdx is absolute to the text. This is updated later to be relative to the parent tag
|
6642
|
+
currentOpenTag.content = text.substring(currentOpenTag.openTagIndex + currentOpenTag.openTagBody.length, foundHtmlTag.startIdx);
|
6643
|
+
// Insert the plain text pieces for the sub tags
|
6644
|
+
if (currentOpenTag.tagType === MSFT_MENTION_TAG) {
|
6645
|
+
plainTextRepresentation =
|
6646
|
+
plainTextRepresentation.slice(0, currentOpenTag.plainTextBeginIndex) +
|
6647
|
+
trigger +
|
6648
|
+
plainTextRepresentation.slice(currentOpenTag.plainTextBeginIndex);
|
6649
|
+
}
|
6650
|
+
if (!currentOpenTag.subTags) {
|
6651
|
+
plainTextRepresentation += currentOpenTag.content;
|
6825
6652
|
}
|
6653
|
+
else if (currentOpenTag.subTags.length > 0) {
|
6654
|
+
// Add text after the last tag
|
6655
|
+
const lastSubTag = currentOpenTag.subTags[currentOpenTag.subTags.length - 1];
|
6656
|
+
const startOfRemainingText = ((_a = lastSubTag.closingTagIndex) !== null && _a !== void 0 ? _a : lastSubTag.openTagIndex) + lastSubTag.tagType.length + 3;
|
6657
|
+
const trailingText = currentOpenTag.content.substring(startOfRemainingText);
|
6658
|
+
plainTextRepresentation += trailingText;
|
6659
|
+
}
|
6660
|
+
currentOpenTag.plainTextEndIndex = plainTextRepresentation.length;
|
6661
|
+
addTag(currentOpenTag, tagParseStack, tags);
|
6826
6662
|
}
|
6827
|
-
else
|
6828
|
-
|
6829
|
-
|
6663
|
+
else {
|
6664
|
+
throw new Error('Unexpected close tag found. Got "' +
|
6665
|
+
closeTagType +
|
6666
|
+
'" but expected "' +
|
6667
|
+
((_b = tagParseStack[tagParseStack.length - 1]) === null || _b === void 0 ? void 0 : _b.tagType) +
|
6668
|
+
'"');
|
6830
6669
|
}
|
6831
6670
|
}
|
6832
|
-
|
6833
|
-
|
6834
|
-
|
6671
|
+
// Update parsing index; move past the end of the close tag
|
6672
|
+
parseIndex = foundHtmlTag.startIdx + foundHtmlTag.content.length;
|
6673
|
+
} // While parseIndex < text.length loop
|
6674
|
+
return { tags, plainText: plainTextRepresentation };
|
6835
6675
|
};
|
6836
|
-
|
6837
|
-
const
|
6838
|
-
|
6839
|
-
|
6840
|
-
|
6676
|
+
const parseOpenTag = (tag, startIdx) => {
|
6677
|
+
const tagType = tag
|
6678
|
+
.substring(1, tag.length - 1)
|
6679
|
+
.split(' ')[0]
|
6680
|
+
.toLowerCase()
|
6681
|
+
.replace('/', '');
|
6682
|
+
return {
|
6683
|
+
tagType,
|
6684
|
+
openTagIndex: startIdx,
|
6685
|
+
openTagBody: tag
|
6686
|
+
};
|
6687
|
+
};
|
6688
|
+
const findNextHtmlTag = (text, startIndex) => {
|
6689
|
+
const tagStartIndex = text.indexOf('<', startIndex);
|
6690
|
+
if (tagStartIndex === -1) {
|
6691
|
+
// No more tags
|
6692
|
+
return undefined;
|
6841
6693
|
}
|
6842
|
-
|
6843
|
-
|
6844
|
-
|
6845
|
-
|
6846
|
-
const firstWordStartIndex = textInput.lastIndexOf(' ', selectionStart);
|
6847
|
-
if (firstWordStartIndex === tag.plainTextBeginIndex) {
|
6848
|
-
start = firstWordStartIndex;
|
6694
|
+
const tagEndIndex = text.indexOf('>', tagStartIndex);
|
6695
|
+
if (tagEndIndex === -1) {
|
6696
|
+
// No close tag
|
6697
|
+
return undefined;
|
6849
6698
|
}
|
6850
|
-
|
6851
|
-
|
6699
|
+
const tag = text.substring(tagStartIndex, tagEndIndex + 1);
|
6700
|
+
let type = 'open';
|
6701
|
+
if (tag[1] === '/') {
|
6702
|
+
type = 'close';
|
6852
6703
|
}
|
6853
|
-
|
6854
|
-
|
6855
|
-
if (selectionEnd !== undefined && tag.plainTextEndIndex !== undefined) {
|
6856
|
-
const lastWordEndIndex = textInput.indexOf(' ', selectionEnd);
|
6857
|
-
end = Math.max(lastWordEndIndex > -1 ? lastWordEndIndex : tag.plainTextEndIndex, selectionEnd);
|
6704
|
+
else if (tag[tag.length - 2] === '/') {
|
6705
|
+
type = 'self-closing';
|
6858
6706
|
}
|
6859
|
-
return {
|
6707
|
+
return {
|
6708
|
+
content: tag,
|
6709
|
+
startIdx: tagStartIndex,
|
6710
|
+
type
|
6711
|
+
};
|
6860
6712
|
};
|
6861
|
-
|
6862
|
-
/**
|
6863
|
-
* Find a new the selection index.
|
6864
|
-
*
|
6865
|
-
* @private
|
6866
|
-
* @param props - Props for finding new selection index for mention.
|
6867
|
-
* @returns New selection index if it is inside of a mention tag, otherwise the current selection.
|
6868
|
-
*/
|
6869
|
-
const findNewSelectionIndexForMention = (props) => {
|
6713
|
+
const addTag = (tag, parseStack, tags) => {
|
6870
6714
|
var _a;
|
6871
|
-
|
6872
|
-
|
6873
|
-
if (
|
6874
|
-
tag
|
6875
|
-
|
6876
|
-
tag.
|
6877
|
-
|
6715
|
+
// Add as sub-tag to the parent stack tag, if there is one
|
6716
|
+
const parentTag = parseStack[parseStack.length - 1];
|
6717
|
+
if (parentTag) {
|
6718
|
+
// Adjust the open tag index to be relative to the parent tag
|
6719
|
+
const parentContentStartIdx = parentTag.openTagIndex + parentTag.openTagBody.length;
|
6720
|
+
const relativeIdx = tag.openTagIndex - parentContentStartIdx;
|
6721
|
+
tag.openTagIndex = relativeIdx;
|
6878
6722
|
}
|
6879
|
-
|
6880
|
-
|
6881
|
-
|
6882
|
-
|
6883
|
-
if (spaceIndex === -1) {
|
6884
|
-
// no space before the selection, use the beginning of the tag
|
6885
|
-
spaceIndex = tag.plainTextBeginIndex;
|
6723
|
+
if (!tag.closingTagIndex) {
|
6724
|
+
// If the tag is self-closing, the close tag is the same as the open tag
|
6725
|
+
if (tag.openTagBody[tag.openTagBody.length - 2] === '/') {
|
6726
|
+
tag.closingTagIndex = tag.openTagIndex;
|
6886
6727
|
}
|
6728
|
+
else {
|
6729
|
+
// Otherwise, the close tag index is the open tag index + the open tag body + the content length
|
6730
|
+
tag.closingTagIndex = tag.openTagIndex + tag.openTagBody.length + ((_a = tag.content) !== null && _a !== void 0 ? _a : []).length;
|
6731
|
+
}
|
6732
|
+
}
|
6733
|
+
// Put the tag where it belongs
|
6734
|
+
if (!parentTag) {
|
6735
|
+
tags.push(tag);
|
6887
6736
|
}
|
6888
6737
|
else {
|
6889
|
-
|
6890
|
-
|
6891
|
-
|
6892
|
-
|
6893
|
-
|
6738
|
+
if (!parentTag.subTags) {
|
6739
|
+
parentTag.subTags = [tag];
|
6740
|
+
}
|
6741
|
+
else {
|
6742
|
+
parentTag.subTags.push(tag);
|
6894
6743
|
}
|
6895
6744
|
}
|
6896
|
-
spaceIndex = Math.max(tag.plainTextBeginIndex, spaceIndex);
|
6897
|
-
spaceIndex = Math.min(tag.plainTextEndIndex, spaceIndex);
|
6898
|
-
return spaceIndex;
|
6899
6745
|
};
|
6900
|
-
|
6746
|
+
|
6747
|
+
// Copyright (c) Microsoft Corporation.
|
6901
6748
|
/**
|
6902
|
-
* Handle mention tag edit and by word deleting
|
6903
|
-
*
|
6904
6749
|
* @private
|
6905
|
-
*
|
6906
|
-
* @returns Updated texts and indexes.
|
6750
|
+
* z-index to ensure that chat container has lower z-index than mention popover
|
6907
6751
|
*/
|
6908
|
-
const
|
6909
|
-
|
6910
|
-
|
6911
|
-
|
6912
|
-
|
6913
|
-
|
6914
|
-
|
6915
|
-
|
6916
|
-
|
6917
|
-
|
6918
|
-
|
6919
|
-
|
6920
|
-
|
6921
|
-
|
6922
|
-
|
6923
|
-
|
6924
|
-
|
6925
|
-
|
6926
|
-
|
6927
|
-
|
6928
|
-
if (rangeStart !== -1 && rangeStart !== undefined && rangeStart > tag.plainTextBeginIndex) {
|
6929
|
-
isSpaceLengthHandled = true;
|
6930
|
-
}
|
6931
|
-
rangeEnd = oldPlainText.indexOf(' ', oldPlainTextEndIndex);
|
6932
|
-
if (rangeEnd === -1 || rangeEnd === undefined) {
|
6933
|
-
// check if space symbol is not found
|
6934
|
-
rangeEnd = plainTextEndIndex;
|
6935
|
-
}
|
6936
|
-
else if (!isSpaceLengthHandled) {
|
6937
|
-
// +1 to include the space symbol
|
6938
|
-
rangeEnd += 1;
|
6939
|
-
}
|
6940
|
-
isSpaceLengthHandled = true;
|
6941
|
-
if (rangeStart === -1 || rangeStart === undefined || rangeStart < tag.plainTextBeginIndex) {
|
6942
|
-
// rangeStart should be at least equal to tag.plainTextBeginIndex
|
6943
|
-
rangeStart = tag.plainTextBeginIndex;
|
6944
|
-
}
|
6945
|
-
if (rangeEnd > plainTextEndIndex) {
|
6946
|
-
// rangeEnd should be at most equal to plainTextEndIndex
|
6947
|
-
rangeEnd = plainTextEndIndex;
|
6948
|
-
}
|
6949
|
-
if (rangeStart === tag.plainTextBeginIndex && rangeEnd === plainTextEndIndex) {
|
6950
|
-
// the whole tag should be removed
|
6951
|
-
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex) + processedChange;
|
6952
|
-
plainTextSelectionEndIndex = tag.plainTextBeginIndex + processedChange.length;
|
6953
|
-
processedChange = '';
|
6954
|
-
lastProcessedHTMLIndex = closeTagIdx + closeTagLength;
|
6955
|
-
}
|
6956
|
-
else {
|
6957
|
-
// only part of the tag should be removed
|
6958
|
-
let startChangeDiff = 0;
|
6959
|
-
let endChangeDiff = 0;
|
6960
|
-
// need to check only rangeStart > tag.plainTextBeginIndex as when rangeStart === tag.plainTextBeginIndex startChangeDiff = 0 and mentionTagLength shouldn't be subtracted
|
6961
|
-
if (rangeStart > tag.plainTextBeginIndex) {
|
6962
|
-
startChangeDiff = rangeStart - tag.plainTextBeginIndex - mentionTagLength;
|
6963
|
-
}
|
6964
|
-
endChangeDiff = rangeEnd - tag.plainTextBeginIndex - mentionTagLength;
|
6965
|
-
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff);
|
6966
|
-
if (startIndex < tag.plainTextBeginIndex) {
|
6967
|
-
// if the change is before the tag, the selection should start from startIndex (rangeStart will be equal to tag.plainTextBeginIndex)
|
6968
|
-
plainTextSelectionEndIndex = startIndex + change.length;
|
6752
|
+
const CHAT_CONTAINER_ZINDEX$1 = 1;
|
6753
|
+
/**
|
6754
|
+
* @private
|
6755
|
+
*/
|
6756
|
+
const mentionPopoverContainerStyle = (theme) => react.mergeStyles({
|
6757
|
+
boxShadow: theme.effects.elevation16,
|
6758
|
+
background: theme.semanticColors.bodyBackground,
|
6759
|
+
overflow: 'visible',
|
6760
|
+
// zIndex to set the mentionPopover above the chat container
|
6761
|
+
zIndex: CHAT_CONTAINER_ZINDEX$1 + 1
|
6762
|
+
});
|
6763
|
+
/**
|
6764
|
+
* @private
|
6765
|
+
*/
|
6766
|
+
const headerStyleThemed = (theme) => {
|
6767
|
+
return {
|
6768
|
+
root: {
|
6769
|
+
color: theme.palette.neutralSecondary,
|
6770
|
+
margin: '0.5rem 1rem 0.25rem',
|
6771
|
+
fontSize: theme.fonts.smallPlus.fontSize
|
6969
6772
|
}
|
6970
|
-
|
6971
|
-
|
6972
|
-
|
6773
|
+
};
|
6774
|
+
};
|
6775
|
+
/**
|
6776
|
+
* @private
|
6777
|
+
*/
|
6778
|
+
react.mergeStyles({
|
6779
|
+
height: '100%',
|
6780
|
+
overflowY: 'visible',
|
6781
|
+
overflowX: 'hidden'
|
6782
|
+
});
|
6783
|
+
/**
|
6784
|
+
* @private
|
6785
|
+
*/
|
6786
|
+
const suggestionListStyle = react.mergeStyles({
|
6787
|
+
padding: '0.25rem 0rem 0',
|
6788
|
+
overflow: 'visible'
|
6789
|
+
});
|
6790
|
+
/**
|
6791
|
+
* @private
|
6792
|
+
*/
|
6793
|
+
const suggestionItemWrapperStyle = (theme) => {
|
6794
|
+
return react.mergeStyles({
|
6795
|
+
margin: '0.05rem 0.1rem',
|
6796
|
+
'&:focus-visible': {
|
6797
|
+
outline: `${theme.palette.black} solid 0.1rem`
|
6973
6798
|
}
|
6974
|
-
|
6975
|
-
// processed change should not be changed as it should be added after the tag
|
6976
|
-
}
|
6977
|
-
return { result, updatedChange: processedChange, htmlIndex: lastProcessedHTMLIndex, plainTextSelectionEndIndex };
|
6799
|
+
});
|
6978
6800
|
};
|
6979
|
-
/* @conditional-compile-remove(mention) */
|
6980
6801
|
/**
|
6981
|
-
* Get closing tag information if exists otherwise return information as for self closing tag
|
6982
|
-
*
|
6983
6802
|
* @private
|
6984
|
-
* @param tag - Tag data.
|
6985
|
-
* @returns Closing tag information for the provided tag.
|
6986
6803
|
*/
|
6987
|
-
const
|
6988
|
-
|
6989
|
-
|
6990
|
-
|
6991
|
-
|
6992
|
-
|
6993
|
-
|
6994
|
-
|
6995
|
-
|
6996
|
-
closeTagLength = tag.tagType.length + 3;
|
6997
|
-
}
|
6998
|
-
else if (tag.plainTextBeginIndex !== undefined) {
|
6999
|
-
// no close tag
|
7000
|
-
plainTextEndIndex = tag.plainTextBeginIndex;
|
7001
|
-
closeTagIdx = tag.openTagIndex + tag.openTagBody.length;
|
7002
|
-
closeTagLength = 0;
|
7003
|
-
}
|
7004
|
-
return { plainTextEndIndex, closeTagIdx, closeTagLength };
|
6804
|
+
const suggestionItemStackStyle = (theme, isSuggestionHovered, activeBorder) => {
|
6805
|
+
return react.mergeStyles({
|
6806
|
+
width: '10rem',
|
6807
|
+
alignItems: 'center',
|
6808
|
+
height: '36px',
|
6809
|
+
padding: '0 0.75rem',
|
6810
|
+
background: isSuggestionHovered ? theme.palette.neutralLight : theme.palette.white,
|
6811
|
+
border: activeBorder ? `0.0625rem solid ${theme.palette.neutralSecondary}` : 'none'
|
6812
|
+
});
|
7005
6813
|
};
|
7006
|
-
|
6814
|
+
|
6815
|
+
// Copyright (c) Microsoft Corporation.
|
7007
6816
|
/**
|
7008
|
-
*
|
6817
|
+
* Component to render a pop-up of mention suggestions.
|
7009
6818
|
*
|
7010
|
-
* @
|
7011
|
-
* @param props - Props for update HTML function.
|
7012
|
-
* @returns Updated HTML and selection index if the selection index should be set.
|
6819
|
+
* @internal
|
7013
6820
|
*/
|
7014
|
-
const
|
7015
|
-
const {
|
7016
|
-
|
7017
|
-
|
7018
|
-
|
7019
|
-
|
7020
|
-
|
7021
|
-
|
7022
|
-
|
7023
|
-
|
7024
|
-
|
7025
|
-
|
7026
|
-
|
7027
|
-
|
7028
|
-
let processedChange = change;
|
7029
|
-
// end tag plain text index of the last processed tag
|
7030
|
-
let lastProcessedPlainTextTagEndIndex = 0;
|
7031
|
-
// as some tags/text can be removed fully, selection should be updated correctly
|
7032
|
-
let changeNewEndIndex;
|
7033
|
-
for (let i = 0; i < tags.length; i++) {
|
7034
|
-
const tag = tags[i];
|
7035
|
-
if (tag.plainTextBeginIndex === undefined) {
|
7036
|
-
continue;
|
6821
|
+
const _MentionPopover = (props) => {
|
6822
|
+
const { suggestions, activeSuggestionIndex, title, target, targetPositionOffset, onRenderSuggestionItem, onSuggestionSelected, onDismiss, location } = props;
|
6823
|
+
const theme = react.useTheme();
|
6824
|
+
/* @conditional-compile-remove(mention) */
|
6825
|
+
const ids = useIdentifiers();
|
6826
|
+
const localeStrings = useLocale$1().strings;
|
6827
|
+
const popoverRef = React.useRef();
|
6828
|
+
const [position, setPosition] = React.useState({ left: 0 });
|
6829
|
+
const [hoveredSuggestion, setHoveredSuggestion] = React.useState(undefined);
|
6830
|
+
const [changedSelection, setChangedSelection] = React.useState(undefined); // Selection UI as per teams
|
6831
|
+
const dismissPopoverWhenClickingOutside = React.useCallback((e) => {
|
6832
|
+
const target = e.target;
|
6833
|
+
if (popoverRef.current && !popoverRef.current.contains(target)) {
|
6834
|
+
onDismiss && onDismiss();
|
7037
6835
|
}
|
7038
|
-
|
7039
|
-
|
7040
|
-
|
7041
|
-
|
7042
|
-
let isMentionTag = false;
|
7043
|
-
if (tag.tagType === MSFT_MENTION_TAG) {
|
7044
|
-
mentionTagLength = mentionTrigger.length;
|
7045
|
-
isMentionTag = true;
|
6836
|
+
}, [onDismiss]);
|
6837
|
+
React.useEffect(() => {
|
6838
|
+
if (changedSelection === undefined) {
|
6839
|
+
setChangedSelection(false);
|
7046
6840
|
}
|
7047
|
-
if (
|
7048
|
-
|
7049
|
-
// Math.max(lastProcessedPlainTextTagEndIndex, startIndex) is used as startIndex may not be in [[previous tag].plainTextEndIndex - tag.plainTextBeginIndex] range
|
7050
|
-
const startChangeDiff = tag.plainTextBeginIndex - Math.max(lastProcessedPlainTextTagEndIndex, startIndex);
|
7051
|
-
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex - startChangeDiff) + processedChange;
|
7052
|
-
processedChange = '';
|
7053
|
-
if (oldPlainTextEndIndex <= tag.plainTextBeginIndex) {
|
7054
|
-
// the whole change is before tag start
|
7055
|
-
// mentionTag length can be ignored here as the change is before the tag
|
7056
|
-
const endChangeDiff = tag.plainTextBeginIndex - oldPlainTextEndIndex;
|
7057
|
-
lastProcessedHTMLIndex = tag.openTagIndex - endChangeDiff;
|
7058
|
-
// the change is handled; exit
|
7059
|
-
break;
|
7060
|
-
}
|
7061
|
-
else {
|
7062
|
-
// change continues in the tag
|
7063
|
-
lastProcessedHTMLIndex = tag.openTagIndex;
|
7064
|
-
// proceed to the next check
|
7065
|
-
}
|
6841
|
+
else if (changedSelection === false) {
|
6842
|
+
setChangedSelection(true);
|
7066
6843
|
}
|
7067
|
-
|
7068
|
-
|
7069
|
-
|
7070
|
-
|
7071
|
-
|
7072
|
-
|
7073
|
-
|
7074
|
-
|
7075
|
-
|
7076
|
-
|
7077
|
-
|
7078
|
-
|
7079
|
-
|
7080
|
-
|
7081
|
-
|
7082
|
-
|
7083
|
-
|
7084
|
-
|
7085
|
-
|
7086
|
-
|
7087
|
-
|
7088
|
-
|
7089
|
-
|
7090
|
-
|
7091
|
-
|
7092
|
-
|
7093
|
-
|
7094
|
-
|
7095
|
-
|
7096
|
-
|
7097
|
-
|
7098
|
-
|
7099
|
-
|
7100
|
-
|
7101
|
-
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
|
7102
|
-
}
|
7103
|
-
processedChange = '';
|
7104
|
-
}
|
7105
|
-
else {
|
7106
|
-
const updateMentionTagResult = handleMentionTagUpdate({
|
7107
|
-
htmlText,
|
7108
|
-
oldPlainText,
|
7109
|
-
lastProcessedHTMLIndex,
|
7110
|
-
processedChange,
|
7111
|
-
change,
|
7112
|
-
tag,
|
7113
|
-
closeTagIdx: closingTagInfo.closeTagIdx,
|
7114
|
-
closeTagLength: closingTagInfo.closeTagLength,
|
7115
|
-
plainTextEndIndex: closingTagInfo.plainTextEndIndex,
|
7116
|
-
startIndex,
|
7117
|
-
oldPlainTextEndIndex,
|
7118
|
-
mentionTagLength
|
7119
|
-
});
|
7120
|
-
result += updateMentionTagResult.result;
|
7121
|
-
changeNewEndIndex = updateMentionTagResult.plainTextSelectionEndIndex;
|
7122
|
-
processedChange = updateMentionTagResult.updatedChange;
|
7123
|
-
lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
|
7124
|
-
}
|
7125
|
-
}
|
7126
|
-
else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
|
7127
|
-
// with subtags
|
7128
|
-
const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
|
7129
|
-
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
|
7130
|
-
const updatedContent = updateHTML({
|
7131
|
-
htmlText: tag.content,
|
7132
|
-
oldPlainText,
|
7133
|
-
newPlainText,
|
7134
|
-
tags: tag.subTags,
|
7135
|
-
startIndex,
|
7136
|
-
oldPlainTextEndIndex,
|
7137
|
-
change: processedChange,
|
7138
|
-
mentionTrigger
|
7139
|
-
});
|
7140
|
-
result += stringBefore + updatedContent.updatedHTML;
|
7141
|
-
changeNewEndIndex = updatedContent.updatedSelectionIndex;
|
7142
|
-
}
|
7143
|
-
else {
|
7144
|
-
// no subtags
|
7145
|
-
const startChangeDiff = startIndex - tag.plainTextBeginIndex;
|
7146
|
-
result +=
|
7147
|
-
htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff) +
|
7148
|
-
processedChange;
|
7149
|
-
processedChange = '';
|
7150
|
-
if (oldPlainTextEndIndex < closingTagInfo.plainTextEndIndex) {
|
7151
|
-
const endChangeDiff = oldPlainTextEndIndex - tag.plainTextBeginIndex;
|
7152
|
-
lastProcessedHTMLIndex = tag.openTagIndex + tag.openTagBody.length + endChangeDiff;
|
7153
|
-
}
|
7154
|
-
else if (oldPlainTextEndIndex === closingTagInfo.plainTextEndIndex) {
|
7155
|
-
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
|
7156
|
-
}
|
7157
|
-
}
|
7158
|
-
// the change is handled; exit
|
6844
|
+
}, [activeSuggestionIndex, changedSelection]);
|
6845
|
+
React.useEffect(() => {
|
6846
|
+
window && window.addEventListener('click', dismissPopoverWhenClickingOutside);
|
6847
|
+
return () => {
|
6848
|
+
window && window.removeEventListener('click', dismissPopoverWhenClickingOutside);
|
6849
|
+
};
|
6850
|
+
}, [dismissPopoverWhenClickingOutside]);
|
6851
|
+
// Determine popover position
|
6852
|
+
React.useEffect(() => {
|
6853
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
6854
|
+
const rect = (_a = target === null || target === void 0 ? void 0 : target.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
6855
|
+
const maxWidth = 200;
|
6856
|
+
const finalPosition = { maxWidth };
|
6857
|
+
// Figure out whether it will fit horizontally
|
6858
|
+
const leftOffset = (_b = targetPositionOffset === null || targetPositionOffset === void 0 ? void 0 : targetPositionOffset.left) !== null && _b !== void 0 ? _b : 0;
|
6859
|
+
if (leftOffset + maxWidth > ((_c = rect === null || rect === void 0 ? void 0 : rect.width) !== null && _c !== void 0 ? _c : 0)) {
|
6860
|
+
finalPosition.right = ((_d = rect === null || rect === void 0 ? void 0 : rect.width) !== null && _d !== void 0 ? _d : 0) - leftOffset;
|
6861
|
+
}
|
6862
|
+
else {
|
6863
|
+
finalPosition.left = leftOffset;
|
6864
|
+
}
|
6865
|
+
if (location === 'below') {
|
6866
|
+
finalPosition.top = ((_e = rect === null || rect === void 0 ? void 0 : rect.height) !== null && _e !== void 0 ? _e : 0) + ((_f = targetPositionOffset === null || targetPositionOffset === void 0 ? void 0 : targetPositionOffset.top) !== null && _f !== void 0 ? _f : 0);
|
6867
|
+
}
|
6868
|
+
else {
|
6869
|
+
// (location === 'above')
|
6870
|
+
finalPosition.bottom = ((_g = rect === null || rect === void 0 ? void 0 : rect.height) !== null && _g !== void 0 ? _g : 0) - ((_h = targetPositionOffset === null || targetPositionOffset === void 0 ? void 0 : targetPositionOffset.top) !== null && _h !== void 0 ? _h : 0);
|
6871
|
+
}
|
6872
|
+
setPosition(finalPosition);
|
6873
|
+
}, [location, target, targetPositionOffset]);
|
6874
|
+
const handleOnKeyDown = React.useCallback((e) => {
|
6875
|
+
switch (e.key) {
|
6876
|
+
case 'Escape':
|
6877
|
+
onDismiss && onDismiss();
|
7159
6878
|
break;
|
6879
|
+
}
|
6880
|
+
}, [onDismiss]);
|
6881
|
+
const personaRenderer = React.useCallback((displayName) => {
|
6882
|
+
const displayNamePlaceholder = localeStrings.participantItem.displayNamePlaceholder;
|
6883
|
+
const avatarOptions = {
|
6884
|
+
text: (displayName === null || displayName === void 0 ? void 0 : displayName.trim()) || displayNamePlaceholder,
|
6885
|
+
size: react.PersonaSize.size24,
|
6886
|
+
initialsColor: theme.palette.neutralLight,
|
6887
|
+
initialsTextColor: theme.palette.neutralSecondary,
|
6888
|
+
showOverflowTooltip: false,
|
6889
|
+
showUnknownPersonaCoin: !(displayName === null || displayName === void 0 ? void 0 : displayName.trim()) || displayName === displayNamePlaceholder
|
6890
|
+
};
|
6891
|
+
return React__default['default'].createElement(react.Persona, Object.assign({}, avatarOptions));
|
6892
|
+
}, [localeStrings, theme]);
|
6893
|
+
const defaultOnRenderSuggestionItem = React.useCallback((suggestion, onSuggestionSelected, active) => {
|
6894
|
+
return (React__default['default'].createElement("div", { "data-is-focusable": true, "data-ui-id": ids.mentionSuggestionItem, key: suggestion.id, onClick: () => onSuggestionSelected(suggestion), onMouseEnter: () => setHoveredSuggestion(suggestion), onMouseLeave: () => setHoveredSuggestion(undefined), onKeyDown: (e) => {
|
6895
|
+
handleOnKeyDown(e);
|
6896
|
+
}, className: suggestionItemWrapperStyle(theme) },
|
6897
|
+
React__default['default'].createElement(react.Stack, { horizontal: true, className: suggestionItemStackStyle(theme, (hoveredSuggestion === null || hoveredSuggestion === void 0 ? void 0 : hoveredSuggestion.id) === suggestion.id, (changedSelection !== null && changedSelection !== void 0 ? changedSelection : false) && active) }, personaRenderer(suggestion.displayText))));
|
6898
|
+
}, [
|
6899
|
+
handleOnKeyDown,
|
6900
|
+
theme,
|
6901
|
+
/* @conditional-compile-remove(mention) */
|
6902
|
+
ids,
|
6903
|
+
hoveredSuggestion,
|
6904
|
+
changedSelection,
|
6905
|
+
personaRenderer
|
6906
|
+
]);
|
6907
|
+
const getHeaderTitle = React.useCallback(() => {
|
6908
|
+
if (title) {
|
6909
|
+
return title;
|
6910
|
+
}
|
6911
|
+
/* @conditional-compile-remove(mention) */
|
6912
|
+
return localeStrings.mentionPopover.mentionPopoverHeader;
|
6913
|
+
}, [localeStrings, title]);
|
6914
|
+
return (React__default['default'].createElement("div", { ref: popoverRef },
|
6915
|
+
React__default['default'].createElement(react.Stack, { className: react.mergeStyles({
|
6916
|
+
maxHeight: 212,
|
6917
|
+
maxWidth: position.maxWidth
|
6918
|
+
}, mentionPopoverContainerStyle(theme), Object.assign(Object.assign({}, position), { position: 'absolute' })) },
|
6919
|
+
React__default['default'].createElement(react.Stack.Item, { styles: headerStyleThemed(theme), "aria-label": title }, getHeaderTitle()),
|
6920
|
+
React__default['default'].createElement(react.Stack
|
6921
|
+
/* @conditional-compile-remove(mention) */
|
6922
|
+
, { "data-ui-id": ids.mentionSuggestionList, className: suggestionListStyle }, suggestions.map((suggestion, index) => {
|
6923
|
+
const active = index === activeSuggestionIndex;
|
6924
|
+
return onRenderSuggestionItem
|
6925
|
+
? onRenderSuggestionItem(suggestion, onSuggestionSelected, active)
|
6926
|
+
: defaultOnRenderSuggestionItem(suggestion, onSuggestionSelected, active);
|
6927
|
+
})))));
|
6928
|
+
};
|
6929
|
+
|
6930
|
+
// Copyright (c) Microsoft Corporation.
|
6931
|
+
// Licensed under the MIT license.
|
6932
|
+
var __awaiter$w = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
|
6933
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
6934
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
6935
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6936
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6937
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
6938
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
6939
|
+
});
|
6940
|
+
};
|
6941
|
+
const DEFAULT_MENTION_TRIGGER = '@';
|
6942
|
+
/**
|
6943
|
+
* @private
|
6944
|
+
*/
|
6945
|
+
const TextFieldWithMention = (props) => {
|
6946
|
+
const { textFieldProps, dataUiId, textValue, onChange, textFieldRef, onKeyDown, onEnterKeyDown, supportNewline, mentionLookupOptions } = props;
|
6947
|
+
const inputBoxRef = React.useRef(null);
|
6948
|
+
// Current suggestion list, provided by the callback
|
6949
|
+
const [mentionSuggestions, setMentionSuggestions] = React.useState([]);
|
6950
|
+
// Current suggestion list, provided by the callback
|
6951
|
+
const [activeSuggestionIndex, setActiveSuggestionIndex] = React.useState(undefined);
|
6952
|
+
// Index of the current trigger character in the text field
|
6953
|
+
const [currentTriggerStartIndex, setCurrentTriggerStartIndex] = React.useState(-1);
|
6954
|
+
const [inputTextValue, setInputTextValue] = React.useState('');
|
6955
|
+
const [tagsValue, setTagsValue] = React.useState([]);
|
6956
|
+
// Index of the previous selection start in the text field
|
6957
|
+
const [selectionStartValue, setSelectionStartValue] = React.useState();
|
6958
|
+
// Index of the previous selection end in the text field
|
6959
|
+
const [selectionEndValue, setSelectionEndValue] = React.useState();
|
6960
|
+
// Boolean value to check if onMouseDown event should be handled during select as selection range
|
6961
|
+
// for onMouseDown event is not updated yet and the selection range for mouse click/taps will be
|
6962
|
+
// updated in onSelect event if needed.
|
6963
|
+
const [shouldHandleOnMouseDownDuringSelect, setShouldHandleOnMouseDownDuringSelect] = React.useState(true);
|
6964
|
+
// Point of start of touch/mouse selection
|
6965
|
+
const [interactionStartPoint, setInteractionStartPoint] = React.useState();
|
6966
|
+
// Target selection from mouse movement
|
6967
|
+
const [targetSelection, setTargetSelection] = React.useState();
|
6968
|
+
// Caret position in the text field
|
6969
|
+
const [caretPosition, setCaretPosition] = React.useState(undefined);
|
6970
|
+
// Index of where the caret is in the text field
|
6971
|
+
const [caretIndex, setCaretIndex] = React.useState(undefined);
|
6972
|
+
const localeStrings = useLocale$1().strings;
|
6973
|
+
// Set mention suggestions
|
6974
|
+
const updateMentionSuggestions = React.useCallback((suggestions) => {
|
6975
|
+
setMentionSuggestions(suggestions);
|
6976
|
+
}, [setMentionSuggestions]);
|
6977
|
+
// Parse the text and get the plain text version to display in the input box
|
6978
|
+
React.useEffect(() => {
|
6979
|
+
const trigger = (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) || DEFAULT_MENTION_TRIGGER;
|
6980
|
+
const parsedHTMLData = textToTagParser(textValue, trigger);
|
6981
|
+
setInputTextValue(parsedHTMLData.plainText);
|
6982
|
+
setTagsValue(parsedHTMLData.tags);
|
6983
|
+
updateMentionSuggestions([]);
|
6984
|
+
}, [textValue, mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger, updateMentionSuggestions]);
|
6985
|
+
React.useEffect(() => {
|
6986
|
+
var _a;
|
6987
|
+
// effect for caret index update
|
6988
|
+
if (caretIndex === undefined || textFieldRef === undefined || (textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === undefined) {
|
6989
|
+
return;
|
6990
|
+
}
|
6991
|
+
// get validated caret index between 0 and inputTextValue.length otherwise caret will be set to incorrect index
|
6992
|
+
const updatedCaretIndex = getValidatedIndexInRange({
|
6993
|
+
min: 0,
|
6994
|
+
max: inputTextValue.length,
|
6995
|
+
currentValue: caretIndex
|
6996
|
+
});
|
6997
|
+
(_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.setSelectionRange(updatedCaretIndex, updatedCaretIndex);
|
6998
|
+
setSelectionStartValue(updatedCaretIndex);
|
6999
|
+
setSelectionEndValue(updatedCaretIndex);
|
7000
|
+
}, [caretIndex, inputTextValue.length, textFieldRef, setSelectionStartValue, setSelectionEndValue]);
|
7001
|
+
const onSuggestionSelected = React.useCallback((suggestion) => {
|
7002
|
+
var _a, _b, _c;
|
7003
|
+
let selectionEnd = ((_a = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _a === void 0 ? void 0 : _a.selectionEnd) || -1;
|
7004
|
+
if (selectionEnd < 0) {
|
7005
|
+
selectionEnd = 0;
|
7006
|
+
}
|
7007
|
+
else if (selectionEnd > inputTextValue.length) {
|
7008
|
+
selectionEnd = inputTextValue.length;
|
7009
|
+
}
|
7010
|
+
const oldPlainText = inputTextValue;
|
7011
|
+
const mention = htmlStringForMentionSuggestion(suggestion, localeStrings);
|
7012
|
+
// update plain text with the mention html text
|
7013
|
+
const newPlainText = inputTextValue.substring(0, currentTriggerStartIndex) + mention + inputTextValue.substring(selectionEnd);
|
7014
|
+
const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : DEFAULT_MENTION_TRIGGER;
|
7015
|
+
// update html text with updated plain text
|
7016
|
+
const updatedContent = updateHTML({
|
7017
|
+
htmlText: textValue,
|
7018
|
+
oldPlainText,
|
7019
|
+
newPlainText,
|
7020
|
+
tags: tagsValue,
|
7021
|
+
startIndex: currentTriggerStartIndex,
|
7022
|
+
oldPlainTextEndIndex: selectionEnd,
|
7023
|
+
change: mention,
|
7024
|
+
mentionTrigger: triggerText
|
7025
|
+
});
|
7026
|
+
const displayName = getDisplayNameForMentionSuggestion(suggestion, localeStrings);
|
7027
|
+
const newCaretIndex = currentTriggerStartIndex + displayName.length + triggerText.length;
|
7028
|
+
// move the caret in the text field to the end of the mention plain text
|
7029
|
+
setCaretIndex(newCaretIndex);
|
7030
|
+
setSelectionEndValue(newCaretIndex);
|
7031
|
+
setSelectionStartValue(newCaretIndex);
|
7032
|
+
setCurrentTriggerStartIndex(-1);
|
7033
|
+
updateMentionSuggestions([]);
|
7034
|
+
// set focus back to text field
|
7035
|
+
(_c = textFieldRef === null || textFieldRef === void 0 ? void 0 : textFieldRef.current) === null || _c === void 0 ? void 0 : _c.focus();
|
7036
|
+
setActiveSuggestionIndex(undefined);
|
7037
|
+
onChange && onChange(undefined, updatedContent.updatedHTML);
|
7038
|
+
}, [
|
7039
|
+
textFieldRef,
|
7040
|
+
inputTextValue,
|
7041
|
+
currentTriggerStartIndex,
|
7042
|
+
mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger,
|
7043
|
+
onChange,
|
7044
|
+
textValue,
|
7045
|
+
tagsValue,
|
7046
|
+
updateMentionSuggestions,
|
7047
|
+
localeStrings
|
7048
|
+
]);
|
7049
|
+
const onTextFieldKeyDown = React.useCallback((ev) => {
|
7050
|
+
// caretIndex should be set to undefined when the user is typing
|
7051
|
+
setCaretIndex(undefined);
|
7052
|
+
// shouldHandleOnMouseDownDuringSelect should be set to false after the last mouse down event.
|
7053
|
+
// it shouldn't be updated in onMouseUp
|
7054
|
+
// as onMouseUp can be triggered before or after onSelect event
|
7055
|
+
// because its order depends on mouse events not selection.
|
7056
|
+
setShouldHandleOnMouseDownDuringSelect(false);
|
7057
|
+
if (isEnterKeyEventFromCompositionSession(ev)) {
|
7058
|
+
return;
|
7059
|
+
}
|
7060
|
+
if (mentionSuggestions.length > 0) {
|
7061
|
+
if (ev.key === 'ArrowUp') {
|
7062
|
+
ev.preventDefault();
|
7063
|
+
const newActiveIndex = activeSuggestionIndex === undefined
|
7064
|
+
? mentionSuggestions.length - 1
|
7065
|
+
: Math.max(activeSuggestionIndex - 1, 0);
|
7066
|
+
setActiveSuggestionIndex(newActiveIndex);
|
7160
7067
|
}
|
7161
|
-
else if (
|
7162
|
-
|
7163
|
-
const
|
7164
|
-
|
7165
|
-
|
7166
|
-
|
7167
|
-
oldPlainText,
|
7168
|
-
lastProcessedHTMLIndex,
|
7169
|
-
processedChange: '',
|
7170
|
-
change,
|
7171
|
-
tag,
|
7172
|
-
closeTagIdx: closingTagInfo.closeTagIdx,
|
7173
|
-
closeTagLength: closingTagInfo.closeTagLength,
|
7174
|
-
plainTextEndIndex: closingTagInfo.plainTextEndIndex,
|
7175
|
-
startIndex,
|
7176
|
-
oldPlainTextEndIndex,
|
7177
|
-
mentionTagLength
|
7178
|
-
});
|
7179
|
-
result += updateMentionTagResult.result;
|
7180
|
-
lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
|
7181
|
-
// no need to handle plainTextSelectionEndIndex as the change will be added later
|
7182
|
-
}
|
7183
|
-
else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
|
7184
|
-
// with subtags
|
7185
|
-
const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
|
7186
|
-
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
|
7187
|
-
const updatedContent = updateHTML({
|
7188
|
-
htmlText: tag.content,
|
7189
|
-
oldPlainText,
|
7190
|
-
newPlainText,
|
7191
|
-
tags: tag.subTags,
|
7192
|
-
startIndex,
|
7193
|
-
oldPlainTextEndIndex,
|
7194
|
-
change: '',
|
7195
|
-
mentionTrigger
|
7196
|
-
});
|
7197
|
-
result += stringBefore + updatedContent.updatedHTML;
|
7198
|
-
}
|
7199
|
-
else {
|
7200
|
-
// no subtags
|
7201
|
-
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length + startChangeDiff);
|
7202
|
-
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
|
7203
|
-
}
|
7204
|
-
// proceed with the next calculations
|
7205
|
-
}
|
7206
|
-
else if (startIndex < tag.plainTextBeginIndex && oldPlainTextEndIndex > closingTagInfo.plainTextEndIndex) {
|
7207
|
-
// the change starts before the tag and finishes after it
|
7208
|
-
// tag should be removed, no matter if there are subtags
|
7209
|
-
// no need to save anything between lastProcessedHTMLIndex and closeTagIdx + closeTagLength
|
7210
|
-
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
|
7211
|
-
// proceed with the next calculations
|
7068
|
+
else if (ev.key === 'ArrowDown') {
|
7069
|
+
ev.preventDefault();
|
7070
|
+
const newActiveIndex = activeSuggestionIndex === undefined
|
7071
|
+
? 0
|
7072
|
+
: Math.min(activeSuggestionIndex + 1, mentionSuggestions.length - 1);
|
7073
|
+
setActiveSuggestionIndex(newActiveIndex);
|
7212
7074
|
}
|
7213
|
-
else if (
|
7214
|
-
|
7215
|
-
// tag should be removed, no matter if there are subtags
|
7216
|
-
result += htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex);
|
7217
|
-
// processedChange shouldn't be updated as it will be added after the tag
|
7218
|
-
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength;
|
7219
|
-
// proceed with the next calculations
|
7075
|
+
else if (ev.key === 'Escape') {
|
7076
|
+
updateMentionSuggestions([]);
|
7220
7077
|
}
|
7221
|
-
|
7222
|
-
|
7223
|
-
|
7224
|
-
|
7225
|
-
|
7226
|
-
|
7227
|
-
|
7228
|
-
|
7229
|
-
|
7230
|
-
change,
|
7231
|
-
tag,
|
7232
|
-
closeTagIdx: closingTagInfo.closeTagIdx,
|
7233
|
-
closeTagLength: closingTagInfo.closeTagLength,
|
7234
|
-
plainTextEndIndex: closingTagInfo.plainTextEndIndex,
|
7235
|
-
startIndex,
|
7236
|
-
oldPlainTextEndIndex,
|
7237
|
-
mentionTagLength
|
7238
|
-
});
|
7239
|
-
changeNewEndIndex = updateMentionTagResult.plainTextSelectionEndIndex;
|
7240
|
-
result += updateMentionTagResult.result;
|
7241
|
-
lastProcessedHTMLIndex = updateMentionTagResult.htmlIndex;
|
7242
|
-
}
|
7243
|
-
else if (tag.subTags !== undefined && tag.subTags.length !== 0 && tag.content !== undefined) {
|
7244
|
-
// with subtags
|
7245
|
-
const stringBefore = htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length);
|
7246
|
-
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx;
|
7247
|
-
const updatedContent = updateHTML({
|
7248
|
-
htmlText: tag.content,
|
7249
|
-
oldPlainText,
|
7250
|
-
newPlainText,
|
7251
|
-
tags: tag.subTags,
|
7252
|
-
startIndex,
|
7253
|
-
oldPlainTextEndIndex,
|
7254
|
-
change: processedChange,
|
7255
|
-
mentionTrigger
|
7256
|
-
});
|
7257
|
-
processedChange = '';
|
7258
|
-
result += stringBefore + updatedContent.updatedHTML;
|
7259
|
-
}
|
7260
|
-
else {
|
7261
|
-
// no subtags
|
7262
|
-
result +=
|
7263
|
-
htmlText.substring(lastProcessedHTMLIndex, tag.openTagIndex + tag.openTagBody.length) + processedChange;
|
7264
|
-
processedChange = '';
|
7265
|
-
// oldPlainTextEndIndex already includes mentionTag length
|
7266
|
-
const endChangeDiff = closingTagInfo.plainTextEndIndex - oldPlainTextEndIndex;
|
7267
|
-
// as change may be before the end of the tag, we need to add the rest of the tag
|
7268
|
-
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx - endChangeDiff;
|
7078
|
+
}
|
7079
|
+
if (ev.key === 'Enter' && (ev.shiftKey === false || !supportNewline)) {
|
7080
|
+
ev.preventDefault();
|
7081
|
+
// If we are looking up a mention, select the focused suggestion
|
7082
|
+
if (mentionSuggestions.length > 0 && activeSuggestionIndex !== undefined) {
|
7083
|
+
const selectedMention = mentionSuggestions[activeSuggestionIndex];
|
7084
|
+
if (selectedMention) {
|
7085
|
+
onSuggestionSelected(selectedMention);
|
7086
|
+
return;
|
7269
7087
|
}
|
7270
|
-
// the change is handled; exit
|
7271
|
-
break;
|
7272
7088
|
}
|
7273
|
-
|
7089
|
+
onEnterKeyDown && onEnterKeyDown();
|
7274
7090
|
}
|
7275
|
-
|
7276
|
-
|
7277
|
-
|
7278
|
-
|
7279
|
-
|
7280
|
-
|
7281
|
-
|
7282
|
-
|
7283
|
-
|
7284
|
-
|
7285
|
-
|
7286
|
-
|
7287
|
-
|
7288
|
-
|
7289
|
-
|
7290
|
-
lastProcessedHTMLIndex = closingTagInfo.closeTagIdx + closingTagInfo.closeTagLength + endChangeDiff;
|
7291
|
-
// the change is handled; exit
|
7292
|
-
// break is not required here as this is the last element but added for consistency
|
7293
|
-
break;
|
7091
|
+
onKeyDown && onKeyDown(ev);
|
7092
|
+
}, [
|
7093
|
+
onEnterKeyDown,
|
7094
|
+
onKeyDown,
|
7095
|
+
supportNewline,
|
7096
|
+
mentionSuggestions,
|
7097
|
+
activeSuggestionIndex,
|
7098
|
+
onSuggestionSelected,
|
7099
|
+
updateMentionSuggestions
|
7100
|
+
]);
|
7101
|
+
const debouncedQueryUpdate = useDebounce.useDebouncedCallback((query) => __awaiter$w(void 0, void 0, void 0, function* () {
|
7102
|
+
var _a;
|
7103
|
+
const suggestions = (_a = (yield (mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.onQueryUpdated(query)))) !== null && _a !== void 0 ? _a : [];
|
7104
|
+
if (suggestions.length === 0) {
|
7105
|
+
setActiveSuggestionIndex(undefined);
|
7294
7106
|
}
|
7295
|
-
|
7296
|
-
|
7297
|
-
|
7298
|
-
|
7299
|
-
|
7300
|
-
|
7301
|
-
|
7302
|
-
|
7303
|
-
|
7304
|
-
|
7305
|
-
|
7306
|
-
|
7307
|
-
|
7308
|
-
|
7309
|
-
|
7310
|
-
const
|
7311
|
-
|
7312
|
-
|
7313
|
-
|
7314
|
-
|
7315
|
-
|
7316
|
-
|
7317
|
-
|
7318
|
-
|
7319
|
-
|
7320
|
-
|
7321
|
-
|
7322
|
-
|
7323
|
-
|
7324
|
-
|
7325
|
-
|
7326
|
-
// change is found
|
7327
|
-
newChangeEnd = newTextLength;
|
7328
|
-
oldChangeEnd = oldTextLength;
|
7107
|
+
else if (activeSuggestionIndex === undefined) {
|
7108
|
+
// Set the active to the first, if it's not already set
|
7109
|
+
setActiveSuggestionIndex(0);
|
7110
|
+
}
|
7111
|
+
updateMentionSuggestions(suggestions);
|
7112
|
+
}), 500);
|
7113
|
+
// Update selections index in mention to navigate by words
|
7114
|
+
const updateSelectionIndexesWithMentionIfNeeded = React.useCallback(({ event, inputTextValue, selectionEndValue, selectionStartValue, tagsValue }) => {
|
7115
|
+
var _a, _b, _c;
|
7116
|
+
let updatedStartIndex = event.currentTarget.selectionStart;
|
7117
|
+
let updatedEndIndex = event.currentTarget.selectionEnd;
|
7118
|
+
if (event.currentTarget.selectionStart === event.currentTarget.selectionEnd &&
|
7119
|
+
event.currentTarget.selectionStart !== null &&
|
7120
|
+
event.currentTarget.selectionStart !== -1) {
|
7121
|
+
// just a caret movement/usual typing or deleting
|
7122
|
+
const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
|
7123
|
+
// don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
|
7124
|
+
if (mentionTag !== undefined &&
|
7125
|
+
mentionTag.plainTextBeginIndex !== undefined &&
|
7126
|
+
event.currentTarget.selectionStart > mentionTag.plainTextBeginIndex &&
|
7127
|
+
event.currentTarget.selectionStart < ((_a = mentionTag.plainTextEndIndex) !== null && _a !== void 0 ? _a : mentionTag.plainTextBeginIndex)) {
|
7128
|
+
// get updated selection index
|
7129
|
+
const newSelectionIndex = findNewSelectionIndexForMention({
|
7130
|
+
tag: mentionTag,
|
7131
|
+
textValue: inputTextValue,
|
7132
|
+
currentSelectionIndex: event.currentTarget.selectionStart,
|
7133
|
+
previousSelectionIndex: selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : inputTextValue.length
|
7134
|
+
});
|
7135
|
+
updatedStartIndex = newSelectionIndex;
|
7136
|
+
updatedEndIndex = newSelectionIndex;
|
7137
|
+
}
|
7329
7138
|
}
|
7330
|
-
else {
|
7331
|
-
|
7332
|
-
|
7333
|
-
|
7334
|
-
|
7335
|
-
|
7336
|
-
|
7139
|
+
else if (event.currentTarget.selectionStart !== event.currentTarget.selectionEnd) {
|
7140
|
+
// Both e.currentTarget.selectionStart !== selectionStartValue and e.currentTarget.selectionEnd !== selectionEndValue can be true when a user selects a text by double click
|
7141
|
+
if (event.currentTarget.selectionStart !== null && event.currentTarget.selectionStart !== selectionStartValue) {
|
7142
|
+
// the selection start is changed
|
7143
|
+
const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionStart);
|
7144
|
+
// don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
|
7145
|
+
if (mentionTag !== undefined &&
|
7146
|
+
mentionTag.plainTextBeginIndex !== undefined &&
|
7147
|
+
event.currentTarget.selectionStart > mentionTag.plainTextBeginIndex &&
|
7148
|
+
event.currentTarget.selectionStart < ((_b = mentionTag.plainTextEndIndex) !== null && _b !== void 0 ? _b : mentionTag.plainTextBeginIndex)) {
|
7149
|
+
updatedStartIndex = findNewSelectionIndexForMention({
|
7150
|
+
tag: mentionTag,
|
7151
|
+
textValue: inputTextValue,
|
7152
|
+
currentSelectionIndex: event.currentTarget.selectionStart,
|
7153
|
+
previousSelectionIndex: selectionStartValue !== null && selectionStartValue !== void 0 ? selectionStartValue : inputTextValue.length
|
7154
|
+
});
|
7155
|
+
}
|
7156
|
+
}
|
7157
|
+
if (event.currentTarget.selectionEnd !== null && event.currentTarget.selectionEnd !== selectionEndValue) {
|
7158
|
+
// the selection end is changed
|
7159
|
+
const mentionTag = findMentionTagForSelection(tagsValue, event.currentTarget.selectionEnd);
|
7160
|
+
// don't include boundary cases to show correct selection, otherwise it will show selection at mention boundaries
|
7161
|
+
if (mentionTag !== undefined &&
|
7162
|
+
mentionTag.plainTextBeginIndex !== undefined &&
|
7163
|
+
event.currentTarget.selectionEnd > mentionTag.plainTextBeginIndex &&
|
7164
|
+
event.currentTarget.selectionEnd < ((_c = mentionTag.plainTextEndIndex) !== null && _c !== void 0 ? _c : mentionTag.plainTextBeginIndex)) {
|
7165
|
+
updatedEndIndex = findNewSelectionIndexForMention({
|
7166
|
+
tag: mentionTag,
|
7167
|
+
textValue: inputTextValue,
|
7168
|
+
currentSelectionIndex: event.currentTarget.selectionEnd,
|
7169
|
+
previousSelectionIndex: selectionEndValue !== null && selectionEndValue !== void 0 ? selectionEndValue : inputTextValue.length
|
7170
|
+
});
|
7337
7171
|
}
|
7338
7172
|
}
|
7339
|
-
// make indexes exclusive
|
7340
|
-
newChangeEnd += 1;
|
7341
|
-
oldChangeEnd += 1;
|
7342
7173
|
}
|
7343
|
-
|
7344
|
-
|
7345
|
-
|
7346
|
-
if (newTextLength === changeStart) {
|
7347
|
-
// when change was at the end of string
|
7348
|
-
// change is found
|
7349
|
-
newChangeEnd = newTextLength;
|
7350
|
-
oldChangeEnd = oldTextLength;
|
7174
|
+
// e.currentTarget.selectionDirection should be set to handle shift + arrow keys
|
7175
|
+
if (event.currentTarget.selectionDirection === null) {
|
7176
|
+
event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex);
|
7351
7177
|
}
|
7352
7178
|
else {
|
7353
|
-
|
7354
|
-
newChangeEnd = newTextLength - i - 1;
|
7355
|
-
oldChangeEnd = oldTextLength - i - 1;
|
7356
|
-
if (newText[newChangeEnd] !== oldText[oldChangeEnd]) {
|
7357
|
-
// change is found
|
7358
|
-
break;
|
7359
|
-
}
|
7360
|
-
}
|
7361
|
-
// make indexes exclusive
|
7362
|
-
newChangeEnd += 1;
|
7363
|
-
oldChangeEnd += 1;
|
7179
|
+
event.currentTarget.setSelectionRange(updatedStartIndex, updatedEndIndex, event.currentTarget.selectionDirection);
|
7364
7180
|
}
|
7365
|
-
|
7366
|
-
|
7367
|
-
|
7368
|
-
|
7369
|
-
|
7370
|
-
|
7371
|
-
|
7372
|
-
|
7373
|
-
|
7181
|
+
setSelectionStartValue(nullToUndefined(updatedStartIndex));
|
7182
|
+
setSelectionEndValue(nullToUndefined(updatedEndIndex));
|
7183
|
+
}, [setSelectionStartValue, setSelectionEndValue]);
|
7184
|
+
const handleOnSelect = React.useCallback(({ event, inputTextValue, tags, shouldHandleOnMouseDownDuringSelect, selectionStartValue, selectionEndValue }) => {
|
7185
|
+
if (shouldHandleOnMouseDownDuringSelect) {
|
7186
|
+
if (targetSelection !== undefined) {
|
7187
|
+
setSelectionStartValue(targetSelection.start);
|
7188
|
+
setSelectionEndValue(targetSelection.end);
|
7189
|
+
event.currentTarget.setSelectionRange(targetSelection.start, undefinedToNull(targetSelection.end));
|
7190
|
+
setTargetSelection(undefined);
|
7191
|
+
}
|
7192
|
+
else if (event.currentTarget.selectionStart !== null) {
|
7193
|
+
// on select was triggered by mouse down/up with no movement
|
7194
|
+
const mentionTag = findMentionTagForSelection(tags, event.currentTarget.selectionStart);
|
7195
|
+
if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
|
7196
|
+
// handle mention click
|
7197
|
+
// Get range of word that was clicked on
|
7198
|
+
const selectionRange = rangeOfWordInSelection({
|
7199
|
+
textInput: inputTextValue,
|
7200
|
+
selectionStart: event.currentTarget.selectionStart,
|
7201
|
+
selectionEnd: nullToUndefined(event.currentTarget.selectionEnd),
|
7202
|
+
tag: mentionTag
|
7203
|
+
});
|
7204
|
+
if (event.currentTarget.selectionDirection === null) {
|
7205
|
+
event.currentTarget.setSelectionRange(selectionRange.start, selectionRange.end);
|
7206
|
+
}
|
7207
|
+
else {
|
7208
|
+
event.currentTarget.setSelectionRange(selectionRange.start, selectionRange.end, event.currentTarget.selectionDirection);
|
7209
|
+
}
|
7210
|
+
setSelectionStartValue(selectionRange.start);
|
7211
|
+
setSelectionEndValue(selectionRange.end);
|
7212
|
+
}
|
7213
|
+
else {
|
7214
|
+
setSelectionStartValue(event.currentTarget.selectionStart);
|
7215
|
+
setSelectionEndValue(nullToUndefined(event.currentTarget.selectionEnd));
|
7216
|
+
}
|
7374
7217
|
}
|
7375
7218
|
}
|
7376
|
-
|
7377
|
-
|
7378
|
-
|
7219
|
+
else {
|
7220
|
+
// selection was changed by keyboard
|
7221
|
+
updateSelectionIndexesWithMentionIfNeeded({
|
7222
|
+
event,
|
7223
|
+
inputTextValue,
|
7224
|
+
selectionStartValue,
|
7225
|
+
selectionEndValue,
|
7226
|
+
tagsValue: tags
|
7227
|
+
});
|
7379
7228
|
}
|
7380
|
-
|
7381
|
-
|
7229
|
+
// don't set setShouldHandleOnMouseDownDuringSelect(false) here as setSelectionRange
|
7230
|
+
// could trigger additional calls of onSelect event and they may not be handled correctly
|
7231
|
+
// (because of setSelectionRange calls or rerender)
|
7232
|
+
}, [
|
7233
|
+
updateSelectionIndexesWithMentionIfNeeded,
|
7234
|
+
targetSelection,
|
7235
|
+
setTargetSelection,
|
7236
|
+
setSelectionStartValue,
|
7237
|
+
setSelectionEndValue
|
7238
|
+
]);
|
7239
|
+
const handleOnChange = React.useCallback(({ currentSelectionEnd, currentSelectionStart, currentTriggerStartIndex, event, htmlTextValue, inputTextValue, previousSelectionEnd, previousSelectionStart, tagsValue, updatedValue }) => __awaiter$w(void 0, void 0, void 0, function* () {
|
7240
|
+
var _b;
|
7241
|
+
debouncedQueryUpdate.cancel();
|
7242
|
+
if (event.currentTarget === null) {
|
7243
|
+
return;
|
7382
7244
|
}
|
7383
|
-
|
7384
|
-
|
7385
|
-
|
7386
|
-
|
7387
|
-
|
7388
|
-
|
7389
|
-
|
7390
|
-
|
7391
|
-
|
7392
|
-
|
7393
|
-
|
7394
|
-
|
7395
|
-
const
|
7396
|
-
|
7397
|
-
|
7398
|
-
|
7399
|
-
|
7400
|
-
|
7401
|
-
|
7402
|
-
|
7403
|
-
|
7404
|
-
|
7405
|
-
|
7406
|
-
|
7407
|
-
|
7408
|
-
|
7409
|
-
|
7410
|
-
|
7411
|
-
|
7412
|
-
|
7413
|
-
|
7414
|
-
|
7415
|
-
|
7416
|
-
|
7417
|
-
|
7418
|
-
|
7419
|
-
|
7420
|
-
|
7421
|
-
|
7422
|
-
|
7423
|
-
|
7424
|
-
|
7425
|
-
|
7426
|
-
|
7427
|
-
|
7428
|
-
|
7429
|
-
|
7430
|
-
|
7431
|
-
|
7432
|
-
|
7433
|
-
|
7434
|
-
|
7435
|
-
|
7436
|
-
|
7437
|
-
|
7438
|
-
|
7245
|
+
// handle backspace change
|
7246
|
+
// onSelect is not called for backspace as selection is not changed and local caret index is outdated
|
7247
|
+
setCaretIndex(undefined);
|
7248
|
+
const newValue = updatedValue !== null && updatedValue !== void 0 ? updatedValue : '';
|
7249
|
+
const triggerText = (_b = mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.trigger) !== null && _b !== void 0 ? _b : DEFAULT_MENTION_TRIGGER;
|
7250
|
+
const newTextLength = newValue.length;
|
7251
|
+
// updating indexes to set between 0 and text length, otherwise selectionRange won't be set correctly
|
7252
|
+
const currentSelectionEndValue = getValidatedIndexInRange({
|
7253
|
+
min: 0,
|
7254
|
+
max: newTextLength,
|
7255
|
+
currentValue: currentSelectionEnd
|
7256
|
+
});
|
7257
|
+
const currentSelectionStartValue = getValidatedIndexInRange({
|
7258
|
+
min: 0,
|
7259
|
+
max: newTextLength,
|
7260
|
+
currentValue: currentSelectionStart
|
7261
|
+
});
|
7262
|
+
const previousSelectionStartValue = getValidatedIndexInRange({
|
7263
|
+
min: 0,
|
7264
|
+
max: inputTextValue.length,
|
7265
|
+
currentValue: previousSelectionStart
|
7266
|
+
});
|
7267
|
+
const previousSelectionEndValue = getValidatedIndexInRange({
|
7268
|
+
min: 0,
|
7269
|
+
max: inputTextValue.length,
|
7270
|
+
currentValue: previousSelectionEnd
|
7271
|
+
});
|
7272
|
+
// If we are enabled for lookups,
|
7273
|
+
if (mentionLookupOptions !== undefined) {
|
7274
|
+
// Look at the range of the change for a trigger character
|
7275
|
+
const triggerPriorIndex = newValue.lastIndexOf(triggerText, currentSelectionEndValue - 1);
|
7276
|
+
// Update the caret position, if not doing a lookup
|
7277
|
+
setCaretPosition(textareaCaretTs.Caret.getRelativePosition(event.currentTarget));
|
7278
|
+
if (triggerPriorIndex !== undefined) {
|
7279
|
+
// trigger is found
|
7280
|
+
const isSpaceBeforeTrigger = newValue.substring(triggerPriorIndex - 1, triggerPriorIndex) === ' ';
|
7281
|
+
const wordAtSelection = newValue.substring(triggerPriorIndex, currentSelectionEndValue);
|
7282
|
+
let tagIndex = currentTriggerStartIndex;
|
7283
|
+
if (!isSpaceBeforeTrigger && triggerPriorIndex !== 0) {
|
7284
|
+
//no space before the trigger <- continuation of the previous word
|
7285
|
+
tagIndex = -1;
|
7286
|
+
setCurrentTriggerStartIndex(tagIndex);
|
7287
|
+
}
|
7288
|
+
else if (wordAtSelection === triggerText) {
|
7289
|
+
// start of the mention
|
7290
|
+
tagIndex = currentSelectionEndValue - triggerText.length;
|
7291
|
+
if (tagIndex < 0) {
|
7292
|
+
tagIndex = 0;
|
7293
|
+
}
|
7294
|
+
setCurrentTriggerStartIndex(tagIndex);
|
7295
|
+
}
|
7296
|
+
if (tagIndex === -1) {
|
7297
|
+
updateMentionSuggestions([]);
|
7298
|
+
}
|
7299
|
+
else {
|
7300
|
+
// In the middle of a @mention lookup
|
7301
|
+
if (tagIndex > -1) {
|
7302
|
+
const query = wordAtSelection.substring(triggerText.length, wordAtSelection.length);
|
7303
|
+
if (query !== undefined) {
|
7304
|
+
yield debouncedQueryUpdate(query);
|
7305
|
+
}
|
7306
|
+
}
|
7307
|
+
}
|
7439
7308
|
}
|
7440
|
-
break;
|
7441
7309
|
}
|
7442
|
-
|
7443
|
-
|
7444
|
-
//
|
7445
|
-
|
7446
|
-
|
7447
|
-
|
7448
|
-
|
7449
|
-
|
7450
|
-
|
7451
|
-
|
7452
|
-
|
7453
|
-
|
7454
|
-
|
7310
|
+
let result = '';
|
7311
|
+
if (tagsValue.length === 0) {
|
7312
|
+
// no tags in the string and newValue should be used as a result string
|
7313
|
+
result = newValue;
|
7314
|
+
}
|
7315
|
+
else {
|
7316
|
+
// there are tags in the text value and htmlTextValue is html string
|
7317
|
+
// find diff between old and new text
|
7318
|
+
const { changeStart, oldChangeEnd, newChangeEnd } = findStringsDiffIndexes({
|
7319
|
+
oldText: inputTextValue,
|
7320
|
+
newText: newValue,
|
7321
|
+
previousSelectionStart: previousSelectionStartValue,
|
7322
|
+
previousSelectionEnd: previousSelectionEndValue,
|
7323
|
+
currentSelectionStart: currentSelectionStartValue,
|
7324
|
+
currentSelectionEnd: currentSelectionEndValue
|
7325
|
+
});
|
7326
|
+
const change = newValue.substring(changeStart, newChangeEnd);
|
7327
|
+
// get updated html string
|
7328
|
+
const updatedContent = updateHTML({
|
7329
|
+
htmlText: htmlTextValue,
|
7330
|
+
oldPlainText: inputTextValue,
|
7331
|
+
newPlainText: newValue,
|
7332
|
+
tags: tagsValue,
|
7333
|
+
startIndex: changeStart,
|
7334
|
+
oldPlainTextEndIndex: oldChangeEnd,
|
7335
|
+
change,
|
7336
|
+
mentionTrigger: triggerText
|
7337
|
+
});
|
7338
|
+
result = updatedContent.updatedHTML;
|
7339
|
+
// update caret index if needed
|
7340
|
+
if (updatedContent.updatedSelectionIndex !== undefined) {
|
7341
|
+
setCaretIndex(updatedContent.updatedSelectionIndex);
|
7342
|
+
setSelectionEndValue(updatedContent.updatedSelectionIndex);
|
7343
|
+
setSelectionStartValue(updatedContent.updatedSelectionIndex);
|
7455
7344
|
}
|
7456
7345
|
}
|
7457
|
-
|
7458
|
-
|
7459
|
-
|
7460
|
-
|
7461
|
-
|
7462
|
-
|
7463
|
-
|
7464
|
-
|
7465
|
-
|
7466
|
-
|
7467
|
-
|
7468
|
-
|
7469
|
-
|
7470
|
-
|
7471
|
-
|
7472
|
-
|
7473
|
-
|
7474
|
-
|
7475
|
-
|
7476
|
-
|
7477
|
-
|
7478
|
-
plainTextRepresentation += trailingText;
|
7346
|
+
onChange && onChange(event, result);
|
7347
|
+
}), [onChange, mentionLookupOptions, setCaretIndex, setCaretPosition, updateMentionSuggestions, debouncedQueryUpdate]);
|
7348
|
+
// Adjust the selection range based on a mouse / touch interaction
|
7349
|
+
const handleOnMove = React.useCallback((event) => {
|
7350
|
+
var _a;
|
7351
|
+
let targetStart = event.currentTarget.selectionStart;
|
7352
|
+
let targetEnd = event.currentTarget.selectionEnd;
|
7353
|
+
// Should we do anything?
|
7354
|
+
if (interactionStartPoint !== undefined &&
|
7355
|
+
// And did selection change?
|
7356
|
+
targetStart !== null &&
|
7357
|
+
(targetStart !== (targetSelection === null || targetSelection === void 0 ? void 0 : targetSelection.start) || targetEnd !== (targetSelection === null || targetSelection === void 0 ? void 0 : targetSelection.end))) {
|
7358
|
+
const direction = event.clientX > interactionStartPoint.x ? 'forward' : 'backward';
|
7359
|
+
const mentionTag = findMentionTagForSelection(tagsValue, direction === 'backward'
|
7360
|
+
? event.currentTarget.selectionStart
|
7361
|
+
: (_a = event.currentTarget.selectionEnd) !== null && _a !== void 0 ? _a : event.currentTarget.selectionStart);
|
7362
|
+
let updateCurrentTarget = false;
|
7363
|
+
if (mentionTag !== undefined && mentionTag.plainTextBeginIndex !== undefined) {
|
7364
|
+
targetStart = Math.min(mentionTag.plainTextBeginIndex, targetStart);
|
7365
|
+
if (mentionTag.plainTextEndIndex !== undefined && targetEnd !== null) {
|
7366
|
+
targetEnd = Math.max(mentionTag.plainTextEndIndex, targetEnd);
|
7479
7367
|
}
|
7480
|
-
|
7481
|
-
|
7368
|
+
updateCurrentTarget = true;
|
7369
|
+
setShouldHandleOnMouseDownDuringSelect(false);
|
7482
7370
|
}
|
7483
|
-
|
7484
|
-
|
7485
|
-
|
7486
|
-
|
7487
|
-
|
7488
|
-
'"');
|
7371
|
+
// Update selection range
|
7372
|
+
setTargetSelection({ start: targetStart, end: targetEnd });
|
7373
|
+
if (updateCurrentTarget) {
|
7374
|
+
// Only set the control, if the values are updated
|
7375
|
+
event.currentTarget.setSelectionRange(targetStart, targetEnd, direction);
|
7489
7376
|
}
|
7490
7377
|
}
|
7491
|
-
|
7492
|
-
|
7493
|
-
|
7494
|
-
|
7495
|
-
}
|
7496
|
-
|
7497
|
-
|
7498
|
-
|
7499
|
-
|
7500
|
-
|
7501
|
-
|
7502
|
-
.
|
7503
|
-
|
7504
|
-
|
7505
|
-
|
7506
|
-
|
7507
|
-
|
7508
|
-
|
7509
|
-
|
7510
|
-
|
7511
|
-
|
7512
|
-
|
7513
|
-
|
7514
|
-
|
7515
|
-
|
7516
|
-
|
7517
|
-
|
7518
|
-
|
7519
|
-
|
7520
|
-
|
7521
|
-
|
7522
|
-
|
7523
|
-
|
7524
|
-
|
7525
|
-
|
7526
|
-
|
7527
|
-
|
7528
|
-
|
7529
|
-
|
7530
|
-
|
7531
|
-
|
7532
|
-
|
7533
|
-
|
7378
|
+
}, [setTargetSelection, targetSelection, setShouldHandleOnMouseDownDuringSelect, interactionStartPoint, tagsValue]);
|
7379
|
+
const announcerText = React.useMemo(() => {
|
7380
|
+
if (activeSuggestionIndex === undefined) {
|
7381
|
+
return undefined;
|
7382
|
+
}
|
7383
|
+
const currentMention = mentionSuggestions[activeSuggestionIndex !== null && activeSuggestionIndex !== void 0 ? activeSuggestionIndex : 0];
|
7384
|
+
return (currentMention === null || currentMention === void 0 ? void 0 : currentMention.displayText.length) > 0
|
7385
|
+
? currentMention === null || currentMention === void 0 ? void 0 : currentMention.displayText
|
7386
|
+
: localeStrings.participantItem.displayNamePlaceholder;
|
7387
|
+
}, [activeSuggestionIndex, mentionSuggestions, localeStrings.participantItem.displayNamePlaceholder]);
|
7388
|
+
return (React__default['default'].createElement(React__default['default'].Fragment, null,
|
7389
|
+
mentionSuggestions.length > 0 && (React__default['default'].createElement(_MentionPopover, { suggestions: mentionSuggestions, activeSuggestionIndex: activeSuggestionIndex, target: inputBoxRef, targetPositionOffset: caretPosition, onRenderSuggestionItem: mentionLookupOptions === null || mentionLookupOptions === void 0 ? void 0 : mentionLookupOptions.onRenderSuggestionItem, onSuggestionSelected: onSuggestionSelected, onDismiss: () => {
|
7390
|
+
updateMentionSuggestions([]);
|
7391
|
+
} })),
|
7392
|
+
announcerText !== undefined && React__default['default'].createElement(Announcer$1, { announcementString: announcerText, ariaLive: 'polite' }),
|
7393
|
+
React__default['default'].createElement(react.TextField, Object.assign({}, textFieldProps, { "data-ui-id": dataUiId, value: inputTextValue, onChange: (e, newValue) => {
|
7394
|
+
// Remove when switching to react 17+, currently needed because of https://legacy.reactjs.org/docs/legacy-event-pooling.html
|
7395
|
+
// Prevents React from resetting event's properties
|
7396
|
+
e.persist();
|
7397
|
+
setInputTextValue(newValue !== null && newValue !== void 0 ? newValue : '');
|
7398
|
+
handleOnChange({
|
7399
|
+
event: e,
|
7400
|
+
tagsValue,
|
7401
|
+
htmlTextValue: textValue,
|
7402
|
+
inputTextValue,
|
7403
|
+
currentTriggerStartIndex,
|
7404
|
+
previousSelectionStart: nullToUndefined(selectionStartValue),
|
7405
|
+
previousSelectionEnd: nullToUndefined(selectionEndValue),
|
7406
|
+
currentSelectionStart: nullToUndefined(e.currentTarget.selectionStart),
|
7407
|
+
currentSelectionEnd: nullToUndefined(e.currentTarget.selectionEnd),
|
7408
|
+
updatedValue: newValue
|
7409
|
+
});
|
7410
|
+
}, onSelect: (e) => {
|
7411
|
+
handleOnSelect({
|
7412
|
+
event: e,
|
7413
|
+
inputTextValue,
|
7414
|
+
shouldHandleOnMouseDownDuringSelect,
|
7415
|
+
selectionEndValue,
|
7416
|
+
selectionStartValue,
|
7417
|
+
tags: tagsValue
|
7418
|
+
});
|
7419
|
+
}, onMouseDown: (e) => {
|
7420
|
+
setInteractionStartPoint({ x: e.clientX, y: e.clientY });
|
7421
|
+
// as events order is onMouseDown -> onMouseMove -> onMouseUp -> onSelect -> onClick
|
7422
|
+
// onClick and onMouseDown can't handle clicking on mention event because
|
7423
|
+
// onMouseDown doesn't have correct selectionRange yet and
|
7424
|
+
// onClick already has wrong range as it's called after onSelect that updates the selection range
|
7425
|
+
// so we need to handle onMouseDown to prevent onSelect default behavior
|
7426
|
+
setShouldHandleOnMouseDownDuringSelect(true);
|
7427
|
+
}, onMouseMove: handleOnMove, onMouseUp: () => {
|
7428
|
+
setInteractionStartPoint(undefined);
|
7429
|
+
}, onTouchStart: (e) => {
|
7430
|
+
setInteractionStartPoint({
|
7431
|
+
x: e.targetTouches.item(0).clientX,
|
7432
|
+
y: e.targetTouches.item(0).clientY
|
7433
|
+
});
|
7434
|
+
// see onMouseDown for more details
|
7435
|
+
setShouldHandleOnMouseDownDuringSelect(true);
|
7436
|
+
}, onTouchMove: handleOnMove, onTouchEnd: () => {
|
7437
|
+
setInteractionStartPoint(undefined);
|
7438
|
+
}, onBlur: () => {
|
7439
|
+
// setup all flags to default values when text field loses focus
|
7440
|
+
setShouldHandleOnMouseDownDuringSelect(false);
|
7441
|
+
setCaretIndex(undefined);
|
7442
|
+
setSelectionStartValue(undefined);
|
7443
|
+
setSelectionEndValue(undefined);
|
7444
|
+
}, onKeyDown: onTextFieldKeyDown, elementRef: inputBoxRef }))));
|
7534
7445
|
};
|
7535
|
-
|
7536
|
-
|
7537
|
-
|
7538
|
-
|
7539
|
-
|
7540
|
-
|
7541
|
-
|
7542
|
-
|
7543
|
-
|
7544
|
-
|
7545
|
-
|
7546
|
-
|
7547
|
-
|
7548
|
-
|
7549
|
-
|
7446
|
+
|
7447
|
+
// Copyright (c) Microsoft Corporation.
|
7448
|
+
/**
|
7449
|
+
* @private
|
7450
|
+
*/
|
7451
|
+
const InputBoxComponent = (props) => {
|
7452
|
+
const { styles, id, 'data-ui-id': dataUiId, textValue, onChange, textFieldRef, placeholderText, onKeyDown, onEnterKeyDown, supportNewline, inputClassName, errorMessage, disabled, children } = props;
|
7453
|
+
const mergedRootStyle = react.mergeStyles(inputBoxWrapperStyle, styles === null || styles === void 0 ? void 0 : styles.root);
|
7454
|
+
const mergedInputFieldStyle = react.mergeStyles(inputBoxStyle, inputClassName, props.inlineChildren ? {} : inputBoxNewLineSpaceAffordance);
|
7455
|
+
const mergedTextContainerStyle = react.mergeStyles(textContainerStyle, styles === null || styles === void 0 ? void 0 : styles.textFieldContainer);
|
7456
|
+
const mergedTextFieldStyle = react.concatStyleSets(textFieldStyle, {
|
7457
|
+
fieldGroup: styles === null || styles === void 0 ? void 0 : styles.textField,
|
7458
|
+
errorMessage: styles === null || styles === void 0 ? void 0 : styles.systemMessage,
|
7459
|
+
suffix: {
|
7460
|
+
backgroundColor: 'transparent',
|
7461
|
+
// Remove empty space in the suffix area when adding newline-style buttons
|
7462
|
+
display: props.inlineChildren ? 'flex' : 'contents',
|
7463
|
+
padding: '0 0.25rem'
|
7550
7464
|
}
|
7551
|
-
|
7552
|
-
|
7553
|
-
|
7465
|
+
});
|
7466
|
+
const mergedChildrenStyle = react.mergeStyles(props.inlineChildren ? {} : newLineButtonsContainerStyle);
|
7467
|
+
const onTextFieldKeyDown = React.useCallback((ev) => {
|
7468
|
+
if (isEnterKeyEventFromCompositionSession(ev)) {
|
7469
|
+
return;
|
7554
7470
|
}
|
7555
|
-
|
7556
|
-
|
7557
|
-
|
7558
|
-
tags.push(tag);
|
7559
|
-
}
|
7560
|
-
else {
|
7561
|
-
if (!parentTag.subTags) {
|
7562
|
-
parentTag.subTags = [tag];
|
7471
|
+
if (ev.key === 'Enter' && (ev.shiftKey === false || !supportNewline)) {
|
7472
|
+
ev.preventDefault();
|
7473
|
+
onEnterKeyDown && onEnterKeyDown();
|
7563
7474
|
}
|
7564
|
-
|
7565
|
-
|
7475
|
+
onKeyDown && onKeyDown(ev);
|
7476
|
+
}, [onEnterKeyDown, onKeyDown, supportNewline]);
|
7477
|
+
const onRenderChildren = () => {
|
7478
|
+
return (React__default['default'].createElement(react.Stack, { horizontal: true, className: mergedChildrenStyle }, children));
|
7479
|
+
};
|
7480
|
+
const renderTextField = () => {
|
7481
|
+
const textFieldProps = {
|
7482
|
+
autoFocus: props.autoFocus === 'sendBoxTextField',
|
7483
|
+
multiline: true,
|
7484
|
+
autoAdjustHeight: true,
|
7485
|
+
multiple: false,
|
7486
|
+
resizable: false,
|
7487
|
+
componentRef: textFieldRef,
|
7488
|
+
id,
|
7489
|
+
inputClassName: mergedInputFieldStyle,
|
7490
|
+
placeholder: placeholderText,
|
7491
|
+
autoComplete: 'off',
|
7492
|
+
styles: mergedTextFieldStyle,
|
7493
|
+
disabled,
|
7494
|
+
errorMessage,
|
7495
|
+
onRenderSuffix: onRenderChildren
|
7496
|
+
};
|
7497
|
+
/* @conditional-compile-remove(mention) */
|
7498
|
+
const textFieldWithMentionProps = {
|
7499
|
+
textFieldProps: textFieldProps,
|
7500
|
+
dataUiId: dataUiId,
|
7501
|
+
textValue: textValue,
|
7502
|
+
onChange: onChange,
|
7503
|
+
onKeyDown: onKeyDown,
|
7504
|
+
onEnterKeyDown: onEnterKeyDown,
|
7505
|
+
textFieldRef: textFieldRef,
|
7506
|
+
supportNewline: supportNewline,
|
7507
|
+
mentionLookupOptions: props.mentionLookupOptions
|
7508
|
+
};
|
7509
|
+
/* @conditional-compile-remove(mention) */
|
7510
|
+
if (props.mentionLookupOptions) {
|
7511
|
+
return React__default['default'].createElement(TextFieldWithMention, Object.assign({}, textFieldWithMentionProps));
|
7566
7512
|
}
|
7567
|
-
|
7513
|
+
return (React__default['default'].createElement(react.TextField, Object.assign({}, textFieldProps, { "data-ui-id": dataUiId, value: textValue, onChange: onChange, onKeyDown: onTextFieldKeyDown })));
|
7514
|
+
};
|
7515
|
+
return (React__default['default'].createElement(react.Stack, { className: mergedRootStyle },
|
7516
|
+
React__default['default'].createElement("div", { className: mergedTextContainerStyle }, renderTextField())));
|
7517
|
+
};
|
7518
|
+
/**
|
7519
|
+
* @private
|
7520
|
+
*/
|
7521
|
+
const InputBoxButton = (props) => {
|
7522
|
+
const { onRenderIcon, onClick, ariaLabel, className, id, tooltipContent } = props;
|
7523
|
+
const [isHover, setIsHover] = React.useState(false);
|
7524
|
+
const mergedButtonStyle = react.mergeStyles(inputButtonStyle, className);
|
7525
|
+
const theme = useTheme();
|
7526
|
+
const calloutStyle = { root: { padding: 0 }, calloutMain: { padding: '0.5rem' } };
|
7527
|
+
// Place callout with no gap between it and the button.
|
7528
|
+
const calloutProps = {
|
7529
|
+
gapSpace: 0,
|
7530
|
+
styles: calloutStyle,
|
7531
|
+
backgroundColor: isDarkThemed(theme) ? theme.palette.neutralLighter : ''
|
7532
|
+
};
|
7533
|
+
return (React__default['default'].createElement(react.TooltipHost, { hostClassName: inputButtonTooltipStyle, content: tooltipContent, calloutProps: Object.assign({}, calloutProps) },
|
7534
|
+
React__default['default'].createElement(react.IconButton, { className: mergedButtonStyle, ariaLabel: ariaLabel, onClick: onClick, id: id, onMouseEnter: () => {
|
7535
|
+
setIsHover(true);
|
7536
|
+
}, onMouseLeave: () => {
|
7537
|
+
setIsHover(false);
|
7538
|
+
},
|
7539
|
+
// VoiceOver fix: Avoid icon from stealing focus when IconButton is double-tapped to send message by wrapping with Stack with pointerEvents style to none
|
7540
|
+
onRenderIcon: () => React__default['default'].createElement(react.Stack, { className: iconWrapperStyle$1 }, onRenderIcon(isHover)) })));
|
7568
7541
|
};
|
7569
7542
|
|
7570
7543
|
// Copyright (c) Microsoft Corporation.
|