diff --git a/src/Editor/index.js b/src/Editor/index.js
index 08bf68d54..0cc783364 100644
--- a/src/Editor/index.js
+++ b/src/Editor/index.js
@@ -77,7 +77,7 @@ class WysiwygEditor extends Component {
const newState = {};
const { editorState, contentState } = this.props;
if (!this.state.toolbar) {
- const toolbar = mergeRecursive(defaultToolbar, toolbar);
+ const toolbar = mergeRecursive(defaultToolbar, this.state.toolbar);
newState.toolbar = toolbar;
}
if (
@@ -216,9 +216,14 @@ class WysiwygEditor extends Component {
decorators.push(
...getMentionDecorators({
...this.props.mention,
- onChange: this.onChange,
+ onChange: this.props?.mention?.onChange ? (editorState, selectedSuggestion) => {
+ this.props.mention.onChange(selectedSuggestion, editorState);
+ this.onChange(editorState);
+ } : this.onChange,
getEditorState: this.getEditorState,
- getSuggestions: this.getSuggestions,
+ getSuggestions: this.props?.mention?.getSuggestions ? (mentionText) => {
+ return this.props.mention.getSuggestions(mentionText)
+ } : this.getSuggestions,
getWrapperRef: this.getWrapperRef,
modalHandler: this.modalHandler,
})
diff --git a/src/decorators/Mention/Suggestion/index.js b/src/decorators/Mention/Suggestion/index.js
index f51b92d13..23373849a 100644
--- a/src/decorators/Mention/Suggestion/index.js
+++ b/src/decorators/Mention/Suggestion/index.js
@@ -34,12 +34,11 @@ class Suggestion {
};
}
- findSuggestionEntities = (contentBlock, callback) => {
+ findMentionAttemptText = (contentBlock, callback) => {
if (this.config.getEditorState()) {
const {
separator,
trigger,
- getSuggestions,
getEditorState,
} = this.config;
const selection = getEditorState().getSelection();
@@ -55,230 +54,217 @@ class Suggestion {
: selection.get('focusOffset') + 1
);
let index = text.lastIndexOf(separator + trigger);
- let preText = separator + trigger;
- if ((index === undefined || index < 0) && text[0] === trigger) {
- index = 0;
- preText = trigger;
- }
- if (index >= 0) {
- const mentionText = text.substr(index + preText.length, text.length);
- const suggestionPresent = getSuggestions().some(suggestion => {
- if (suggestion.value) {
- if (this.config.caseSensitive) {
- return suggestion.value.indexOf(mentionText) >= 0;
- }
- return (
- suggestion.value
- .toLowerCase()
- .indexOf(mentionText && mentionText.toLowerCase()) >= 0
- );
- }
- return false;
- });
- if (suggestionPresent) {
- callback(index === 0 ? 0 : index + 1, text.length);
- }
+ if (index >= 0 || text.startsWith(trigger)) {
+ callback(index === 0 ? 0 : index + 1, text.length);
}
}
}
};
- getSuggestionComponent = getSuggestionComponent.bind(this);
+ getCurrentSuggestionsList = async (mentionText) => {
+ const suggestionList = await Promise.resolve(this.config.getSuggestions(mentionText))
+ return suggestionList
+ };
getSuggestionDecorator = () => ({
- strategy: this.findSuggestionEntities,
- component: this.getSuggestionComponent(),
+ strategy: this.findMentionAttemptText,
+ component: SuggestionComponent,
+ props: {
+ config: this.config,
+ getCurrentSuggestionsList: this.getCurrentSuggestionsList
+ }
});
}
-function getSuggestionComponent() {
- const { config } = this;
- return class SuggestionComponent extends Component {
- static propTypes = {
- children: PropTypes.array,
- };
+class SuggestionComponent extends Component {
+ static propTypes = {
+ children: PropTypes.array,
+ };
- state = {
- style: { left: 15 },
- activeOption: -1,
- showSuggestions: true,
- };
+ state = {
+ style: { left: 15 },
+ activeOption: -1,
+ showSuggestions: true,
+ filteredSuggestions: []
+ };
- componentDidMount() {
- const editorRect = config.getWrapperRef().getBoundingClientRect();
- const suggestionRect = this.suggestion.getBoundingClientRect();
- const dropdownRect = this.dropdown.getBoundingClientRect();
- let left;
- let right;
- let bottom;
- if (
- editorRect.width <
- suggestionRect.left - editorRect.left + dropdownRect.width
- ) {
- right = 15;
- } else {
- left = 15;
- }
- if (editorRect.bottom < dropdownRect.bottom) {
- bottom = 0;
- }
+ componentDidMount() {
+ const editorRect = this.props.config.getWrapperRef().getBoundingClientRect();
+ const suggestionRect = this.suggestion.getBoundingClientRect();
+ const dropdownRect = this.dropdown.getBoundingClientRect();
+ let left;
+ let right;
+ let bottom;
+ if (
+ editorRect.width <
+ suggestionRect.left - editorRect.left + dropdownRect.width
+ ) {
+ right = 15;
+ } else {
+ left = 15;
+ }
+ if (editorRect.bottom < dropdownRect.bottom) {
+ bottom = 0;
+ }
+ KeyDownHandler.registerCallBack(this.onEditorKeyDown);
+ SuggestionHandler.open();
+ this.props.config.modalHandler.setSuggestionCallback(this.closeSuggestionDropdown);
+ this.filterSuggestions(this.props).then((_filteredSuggestions) => {
this.setState({
// eslint-disable-line react/no-did-mount-set-state
style: { left, right, bottom },
+ // eslint-disable-line react/no-did-mount-set-state
+ filteredSuggestions: _filteredSuggestions
});
- KeyDownHandler.registerCallBack(this.onEditorKeyDown);
- SuggestionHandler.open();
- config.modalHandler.setSuggestionCallback(this.closeSuggestionDropdown);
- this.filterSuggestions(this.props);
- }
+ });
+ }
- componentDidUpdate(props) {
- const { children } = this.props;
- if (children !== props.children) {
- this.filterSuggestions(props);
+ componentDidUpdate(props) {
+ const { children } = this.props;
+ if (children !== props.children) {
+ this.filterSuggestions(props).then((_filteredSuggestions) => {
this.setState({
showSuggestions: true,
+ filteredSuggestions: _filteredSuggestions
});
- }
+ })
}
+ }
- componentWillUnmount() {
- KeyDownHandler.deregisterCallBack(this.onEditorKeyDown);
+ componentWillUnmount() {
+ KeyDownHandler.deregisterCallBack(this.onEditorKeyDown);
+ SuggestionHandler.close();
+ this.props.config.modalHandler.removeSuggestionCallback();
+ }
+
+ onEditorKeyDown = event => {
+ const { activeOption, filteredSuggestions } = this.state;
+ const newState = {};
+ if (event.key === 'ArrowDown') {
+ event.preventDefault();
+ if (activeOption === filteredSuggestions.length - 1) {
+ newState.activeOption = 0;
+ } else {
+ newState.activeOption = activeOption + 1;
+ }
+ } else if (event.key === 'ArrowUp') {
+ if (activeOption <= 0) {
+ newState.activeOption = filteredSuggestions.length - 1;
+ } else {
+ newState.activeOption = activeOption - 1;
+ }
+ } else if (event.key === 'Escape') {
+ newState.showSuggestions = false;
SuggestionHandler.close();
- config.modalHandler.removeSuggestionCallback();
+ } else if (event.key === 'Enter') {
+ this.addMention();
}
+ this.setState(newState);
+ };
- onEditorKeyDown = event => {
- const { activeOption } = this.state;
- const newState = {};
- if (event.key === 'ArrowDown') {
- event.preventDefault();
- if (activeOption === this.filteredSuggestions.length - 1) {
- newState.activeOption = 0;
- } else {
- newState.activeOption = activeOption + 1;
- }
- } else if (event.key === 'ArrowUp') {
- if (activeOption <= 0) {
- newState.activeOption = this.filteredSuggestions.length - 1;
- } else {
- newState.activeOption = activeOption - 1;
- }
- } else if (event.key === 'Escape') {
- newState.showSuggestions = false;
- SuggestionHandler.close();
- } else if (event.key === 'Enter') {
- this.addMention();
- }
- this.setState(newState);
- };
+ onOptionMouseEnter = event => {
+ const index = event.target.getAttribute('data-index');
+ this.setState({
+ activeOption: index,
+ });
+ };
- onOptionMouseEnter = event => {
- const index = event.target.getAttribute('data-index');
- this.setState({
- activeOption: index,
- });
- };
+ onOptionMouseLeave = () => {
+ this.setState({
+ activeOption: -1,
+ });
+ };
- onOptionMouseLeave = () => {
- this.setState({
- activeOption: -1,
- });
- };
+ setSuggestionReference = ref => {
+ this.suggestion = ref;
+ };
- setSuggestionReference = ref => {
- this.suggestion = ref;
- };
+ setDropdownReference = ref => {
+ this.dropdown = ref;
+ };
- setDropdownReference = ref => {
- this.dropdown = ref;
- };
+ closeSuggestionDropdown = () => {
+ this.setState({
+ showSuggestions: false,
+ });
+ };
- closeSuggestionDropdown = () => {
- this.setState({
- showSuggestions: false,
+ filterSuggestions = async (props) => {
+ const mentionText = props.children[0].props.text.substr(1);
+ const suggestions = await this.props.getCurrentSuggestionsList(mentionText);
+ return suggestions &&
+ suggestions.filter(suggestion => {
+ if (!mentionText || mentionText.length === 0) {
+ return true;
+ }
+ if (this.props.config.caseSensitive) {
+ return suggestion.value.indexOf(mentionText) >= 0;
+ }
+ return (
+ suggestion.value
+ .toLowerCase()
+ .indexOf(mentionText && mentionText.toLowerCase()) >= 0
+ );
});
- };
-
- filteredSuggestions = [];
-
- filterSuggestions = props => {
- const mentionText = props.children[0].props.text.substr(1);
- const suggestions = config.getSuggestions();
- this.filteredSuggestions =
- suggestions &&
- suggestions.filter(suggestion => {
- if (!mentionText || mentionText.length === 0) {
- return true;
- }
- if (config.caseSensitive) {
- return suggestion.value.indexOf(mentionText) >= 0;
- }
- return (
- suggestion.value
- .toLowerCase()
- .indexOf(mentionText && mentionText.toLowerCase()) >= 0
- );
- });
- };
-
- addMention = () => {
- const { activeOption } = this.state;
- const editorState = config.getEditorState();
- const { onChange, separator, trigger } = config;
- const selectedMention = this.filteredSuggestions[activeOption];
- if (selectedMention) {
- addMention(editorState, onChange, separator, trigger, selectedMention);
- }
- };
+ };
- render() {
- const { children } = this.props;
- const { activeOption, showSuggestions } = this.state;
- const { dropdownClassName, optionClassName } = config;
- return (
-
- {children}
- {showSuggestions && (
-
- {this.filteredSuggestions.map((suggestion, index) => (
-
- {suggestion.text}
-
- ))}
-
- )}
-
- );
+ addMention = () => {
+ const { activeOption, filteredSuggestions } = this.state;
+ const editorState = this.props.config.getEditorState();
+ const { onChange, separator, trigger } = this.props.config;
+ const selectedMention = filteredSuggestions?.[activeOption];
+ if (selectedMention) {
+ addMention(editorState, onChange, separator, trigger, selectedMention);
}
};
-}
+
+ render() {
+ const { children } = this.props;
+ const { activeOption, showSuggestions } = this.state;
+ const { dropdownClassName, optionClassName } = this.props.config;
+ return (
+
+ {children}
+ {showSuggestions && (
+
+ {this.state.filteredSuggestions?.map?.((suggestion, index) => (
+
+ {suggestion.text}
+
+ ))}
+
+ )}
+
+ );
+ }
+};
+
export default Suggestion;
diff --git a/src/decorators/Mention/addMention.js b/src/decorators/Mention/addMention.js
index d95cbdba7..9ebaeaaa7 100644
--- a/src/decorators/Mention/addMention.js
+++ b/src/decorators/Mention/addMention.js
@@ -56,5 +56,5 @@ export default function addMention(
undefined,
);
}
- onChange(EditorState.push(newEditorState, contentState, 'insert-characters'));
+ onChange(EditorState.push(newEditorState, contentState, 'insert-characters'), suggestion);
}