I want to implement something like a tag editor. However, it's meant just for those tags so I want the user to see the autocomplete suggestions popup without having to type something like @ or #, just the text itself.
I have something that kinda works, but the popup displays in strange positions on the screen:
Here is an example of a well-known editor of this kind (although not implemented with Draft), so you can get a better understanding of what I want to implement.
First things first, here is the function that triggers the suggestions popup:
private onChange(editorState: EditorState) {
const content = editorState.getCurrentContent();
const selection = editorState.getSelection();
const currentBlock = content.getBlockForKey(selection.getAnchorKey());
if (selection.isCollapsed()) {
const blockText = currentBlock.getText();
const wordMeta = getWordAt(blockText, selection.getAnchorOffset());
const categoryRegex = /([\w]*)/;
const matches = wordMeta.word.match(categoryRegex);
const existingEntity = currentBlock.getEntityAt(wordMeta.begin);
if (!existingEntity && matches) {
const categorySearch = matches[1];
const selection = window.getSelection();
if (this.state.autoComplete.search !== categorySearch && selection.rangeCount > 0) {
const range = selection.getRangeAt(0);
const boundingRect = getRangeBoundingClientRect(range);
this.setState((prevState: StateType) => {
let state = {
autoComplete: {
active: true,
search: categorySearch,
searchMeta: {
begin: wordMeta.begin,
end: wordMeta.end,
},
},
selectionRect: prevState.selectionRect,
};
if (prevState.autoComplete.active === false) {
state.selectionRect = boundingRect;
}
return state;
});
}
}
}
this.props.onChange(editorState);
}
Here is the getWordAt
function:
function getWordAt(text: string, pos: number): WordMeta
{
const left = text.slice(0, pos + 1).search(/\S+$/);
const right = text.slice(pos).search(/\s/);
if (right < 0) {
return {
word: text.slice(left),
begin: left,
end: text.length,
};
}
return {
word: text.slice(left, right + pos),
begin: left,
end: right + pos,
};
}
What would be a better way of handling the position of the popup and maybe even the strategy for autocompletion of this kind as well? Thank you!
Instead Of draft-js-typeahead
- TypeaheadEditor is a react component that wraps draft's Editor. You can use
React-Autosuggest component that meets the requirements. It has custom rendering that works natively with React elements. It's fast and pretty easily customizable. Have full control over suggestions rendering.
We can make it handle JS objects instead of plain strings.
onSuggestionSelected
props is a callback to get the selected suggestionsuggestionRenderer
method takes suggestion and returns React markupCheck out React-Autosuggest.
You can use above component by using a custom block renderer, it is possible to introduce complex rich interactions within the frame of your editor.
You have to break your head to achieve what you want to, its not straight forward. This was my suggestion through which you might achieve it but its not that easy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With