stream-chat
Version:
JS SDK for the Stream Chat API
109 lines (96 loc) • 2.82 kB
text/typescript
import type { TextSelection } from './types';
import { escapeCommandRegExp } from './commandUtils';
/**
* For commands, we want to match all patterns except:
* 1. Text not starting with trigger
* 2. Trigger in middle of text
*/
export const getTriggerCharWithToken = ({
trigger,
text,
isCommand = false,
acceptTrailingSpaces = true,
}: {
trigger: string;
text: string;
isCommand?: boolean;
acceptTrailingSpaces?: boolean;
}) => {
const escapedTrigger = escapeCommandRegExp(trigger);
const triggerNorWhitespace = `[^\\s${escapedTrigger}]*`;
const match = text.match(
new RegExp(
isCommand
? `^[${escapedTrigger}]${triggerNorWhitespace}$`
: acceptTrailingSpaces
? `(?!^|\\W)?[${escapedTrigger}]${triggerNorWhitespace}\\s?${triggerNorWhitespace}$`
: `(?!^|\\W)?[${escapedTrigger}]${triggerNorWhitespace}$`,
'g',
),
);
return match && match[match.length - 1].trim();
};
export const insertItemWithTrigger = ({
insertText,
selection,
text,
trigger,
}: {
insertText: string;
selection: TextSelection;
text: string;
trigger: string;
}) => {
const beforeCursor = text.slice(0, selection.end);
const afterCursor = text.slice(selection.end);
// Replace the trigger and query with the user mention
const lastIndex = beforeCursor.lastIndexOf(trigger);
const newText = beforeCursor.slice(0, lastIndex) + insertText + afterCursor;
return {
text: newText,
selection: {
start: lastIndex + insertText.length,
end: lastIndex + insertText.length,
},
};
};
export const replaceWordWithEntity = async ({
caretPosition,
getEntityString,
text,
}: {
caretPosition: number;
getEntityString: (word: string) => Promise<string | null> | string | null;
text: string;
}): Promise<string> => {
const lastWordRegex = /([^\s]+)(\s*)$/;
const match = lastWordRegex.exec(text.slice(0, caretPosition));
if (!match) return text;
const lastWord = match[1];
if (!lastWord) return text;
const spaces = match[2];
const newWord = await getEntityString(lastWord);
if (newWord == null) return text;
const textBeforeWord = text.slice(0, caretPosition - match[0].length);
const textAfterCaret = text.slice(caretPosition, -1);
return textBeforeWord + newWord + spaces + textAfterCaret;
};
export type TokenizationPayload = {
tokenizedDisplayName: { token: string; parts: string[] };
};
export const getTokenizedSuggestionDisplayName = ({
displayName,
searchToken,
}: {
displayName: string;
searchToken: string;
}): TokenizationPayload => ({
tokenizedDisplayName: {
token: searchToken,
parts: searchToken
? displayName
.split(new RegExp(`(${escapeCommandRegExp(searchToken)})`, 'gi'))
.filter(Boolean)
: [displayName],
},
});