Skip to content

Commit

Permalink
Merge pull request #30412 from aswin-s/fix/naitve-emoji-picker
Browse files Browse the repository at this point in the history
feat: add whitespace after inserting emoji via native keyboard
  • Loading branch information
flodnv authored Nov 3, 2023
2 parents 7a70056 + f2c1022 commit 17ce0c2
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 15 deletions.
6 changes: 5 additions & 1 deletion src/libs/ComposerUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ function canSkipTriggerHotkeys(isSmallScreenWidth: boolean, isKeyboardShown: boo
*/
function getCommonSuffixLength(str1: string, str2: string): number {
let i = 0;
while (str1[str1.length - 1 - i] === str2[str2.length - 1 - i]) {
if (str1.length === 0 || str2.length === 0) {
return 0;
}
const minLen = Math.min(str1.length, str2.length);
while (i < minLen && str1[str1.length - 1 - i] === str2[str2.length - 1 - i]) {
i++;
}
return i;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ function ComposerWithSuggestions({
return draft;
});
const commentRef = useRef(value);
const lastTextRef = useRef(value);

const {isSmallScreenWidth} = useWindowDimensions();
const maxComposerLines = isSmallScreenWidth ? CONST.COMPOSER.MAX_LINES_SMALL_SCREEN : CONST.COMPOSER.MAX_LINES;
Expand Down Expand Up @@ -196,6 +197,50 @@ function ComposerWithSuggestions({
RNTextInputReset.resetKeyboardInput(findNodeHandle(textInputRef.current));
}, [textInputRef]);

/**
* Find the newly added characters between the previous text and the new text based on the selection.
*
* @param {string} prevText - The previous text.
* @param {string} newText - The new text.
* @returns {object} An object containing information about the newly added characters.
* @property {number} startIndex - The start index of the newly added characters in the new text.
* @property {number} endIndex - The end index of the newly added characters in the new text.
* @property {string} diff - The newly added characters.
*/
const findNewlyAddedChars = useCallback(
(prevText, newText) => {
let startIndex = -1;
let endIndex = -1;
let currentIndex = 0;

// Find the first character mismatch with newText
while (currentIndex < newText.length && prevText.charAt(currentIndex) === newText.charAt(currentIndex) && selection.start > currentIndex) {
currentIndex++;
}

if (currentIndex < newText.length) {
startIndex = currentIndex;

// if text is getting pasted over find length of common suffix and subtract it from new text length
if (selection.end - selection.start > 0) {
const commonSuffixLength = ComposerUtils.getCommonSuffixLength(prevText, newText);
endIndex = newText.length - commonSuffixLength;
} else {
endIndex = currentIndex + (newText.length - prevText.length);
}
}

return {
startIndex,
endIndex,
diff: newText.substring(startIndex, endIndex),
};
},
[selection.end, selection.start],
);

const insertWhiteSpace = (text, index) => `${text.slice(0, index)} ${text.slice(index)}`;

const debouncedSaveReportComment = useMemo(
() =>
_.debounce((selectedReportID, newComment) => {
Expand All @@ -213,7 +258,14 @@ function ComposerWithSuggestions({
const updateComment = useCallback(
(commentValue, shouldDebounceSaveComment) => {
raiseIsScrollLikelyLayoutTriggered();
const {text: newComment, emojis} = EmojiUtils.replaceAndExtractEmojis(commentValue, preferredSkinTone, preferredLocale);
const {startIndex, endIndex, diff} = findNewlyAddedChars(lastTextRef.current, commentValue);
const isEmojiInserted = diff.length && endIndex > startIndex && EmojiUtils.containsOnlyEmojis(diff);
const {text: newComment, emojis} = EmojiUtils.replaceAndExtractEmojis(
isEmojiInserted ? insertWhiteSpace(commentValue, endIndex) : commentValue,
preferredSkinTone,
preferredLocale,
);

if (!_.isEmpty(emojis)) {
const newEmojis = EmojiUtils.getAddedEmojis(emojis, emojisPresentBefore.current);
if (!_.isEmpty(newEmojis)) {
Expand Down Expand Up @@ -264,13 +316,14 @@ function ComposerWithSuggestions({
}
},
[
debouncedUpdateFrequentlyUsedEmojis,
preferredLocale,
raiseIsScrollLikelyLayoutTriggered,
findNewlyAddedChars,
preferredSkinTone,
reportID,
preferredLocale,
setIsCommentEmpty,
debouncedUpdateFrequentlyUsedEmojis,
suggestionsRef,
raiseIsScrollLikelyLayoutTriggered,
reportID,
debouncedSaveReportComment,
],
);
Expand Down Expand Up @@ -321,14 +374,8 @@ function ComposerWithSuggestions({
* @param {Boolean} shouldAddTrailSpace
*/
const replaceSelectionWithText = useCallback(
(text, shouldAddTrailSpace = true) => {
const updatedText = shouldAddTrailSpace ? `${text} ` : text;
const selectionSpaceLength = shouldAddTrailSpace ? CONST.SPACE_LENGTH : 0;
updateComment(ComposerUtils.insertText(commentRef.current, selection, updatedText));
setSelection((prevSelection) => ({
start: prevSelection.start + text.length + selectionSpaceLength,
end: prevSelection.start + text.length + selectionSpaceLength,
}));
(text) => {
updateComment(ComposerUtils.insertText(commentRef.current, selection, text));
},
[selection, updateComment],
);
Expand Down Expand Up @@ -452,7 +499,12 @@ function ComposerWithSuggestions({
}

focus();
replaceSelectionWithText(e.key, false);
// Reset cursor to last known location
setSelection((prevSelection) => ({
start: prevSelection.start + 1,
end: prevSelection.end + 1,
}));
replaceSelectionWithText(e.key);
},
[checkComposerVisibility, focus, replaceSelectionWithText],
);
Expand Down Expand Up @@ -514,6 +566,10 @@ function ComposerWithSuggestions({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
lastTextRef.current = value;
}, [value]);

useImperativeHandle(
forwardedRef,
() => ({
Expand Down

0 comments on commit 17ce0c2

Please sign in to comment.