similiquedicta
Version:
A Plugin Architecture on top of Draft.JS
108 lines (90 loc) • 3 kB
text/typescript
import { Modifier, EditorState } from 'draft-js';
import { shortnameToUnicode } from 'emoji-toolkit';
import getSearchText from '../utils/getSearchText';
// This modifier can inserted emoji to current cursor position (with replace selected fragment),
// or replaced emoji shortname like ":thumbsup:". Behavior determined by `Mode` parameter.
const Mode = {
INSERT: 'INSERT', // insert emoji to current cursor position
REPLACE: 'REPLACE', // replace emoji shortname
};
export default function addEmoji(
editorState: EditorState,
emojiShortName: string,
mode = Mode.INSERT
): EditorState {
const emoji = shortnameToUnicode(emojiShortName);
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(
'emoji',
'IMMUTABLE',
{ emojiUnicode: emoji }
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const currentSelectionState = editorState.getSelection();
let emojiAddedContent;
let emojiEndPos = 0;
let blockSize = 0;
switch (mode) {
case Mode.INSERT: {
// in case text is selected it is removed and then the emoji is added
const afterRemovalContentState = Modifier.removeRange(
contentState,
currentSelectionState,
'backward'
);
// deciding on the position to insert emoji
const targetSelection = afterRemovalContentState.getSelectionAfter();
emojiAddedContent = Modifier.insertText(
afterRemovalContentState,
targetSelection,
emoji,
undefined,
entityKey
);
emojiEndPos = targetSelection.getAnchorOffset();
const blockKey = targetSelection.getAnchorKey();
blockSize = contentState.getBlockForKey(blockKey).getLength();
break;
}
case Mode.REPLACE: {
const { begin, end } = getSearchText(editorState, currentSelectionState);
// Get the selection of the :emoji: search text
const emojiTextSelection = currentSelectionState.merge({
anchorOffset: begin,
focusOffset: end,
});
emojiAddedContent = Modifier.replaceText(
contentState,
emojiTextSelection,
emoji,
undefined,
entityKey
);
emojiEndPos = end;
const blockKey = emojiTextSelection.getAnchorKey();
blockSize = contentState.getBlockForKey(blockKey).getLength();
break;
}
default:
throw new Error('Unidentified value of "mode"');
}
// If the emoji is inserted at the end, a space is appended right after for
// a smooth writing experience.
if (emojiEndPos === blockSize) {
emojiAddedContent = Modifier.insertText(
emojiAddedContent,
emojiAddedContent.getSelectionAfter(),
' '
);
}
const newEditorState = EditorState.push(
editorState,
emojiAddedContent,
'insert-fragment'
);
return EditorState.forceSelection(
newEditorState,
emojiAddedContent.getSelectionAfter()
);
}
export { Mode };