I'm not getting any kind of entity data for Mention or Hashtag while using @draft-js-plugins. The link entity only working if I paste the URL directly on the editor. Mention is working fine but the hashtag or URL entity not working.
Hashtag and URL are detected properly on the editor but the editorState is not returning the entity data for hashtag and URL on typing.
import React, { ReactElement, useCallback, useMemo, useRef, useState } from 'react';
import { convertToRaw, EditorState } from 'draft-js';
import Editor, { createEditorStateWithText } from '@draft-js-plugins/editor';
import createHashtagPlugin from '@draft-js-plugins/hashtag';
import createLinkifyPlugin, { extractLinks } from '@draft-js-plugins/linkify';
import tlds from 'tlds';
import linkifyIt from 'linkify-it';
import createMentionPlugin, { defaultSuggestionsFilter } from '@draft-js-plugins/mention';
import editorStyles from './lib/styles/EditorStyles.module.css';
import hashtagStyles from './lib/styles/HashtagStyles.module.css';
import mentionStyles from './lib/styles/MentionStyles.module.css';
import linkStyles from './lib/styles/LinkStyles.module.css';
import '@draft-js-plugins/mention/lib/plugin.css';
import mentions from './lib/data/mentions';
import { EntryComponentProps } from '@draft-js-plugins/mention/lib/MentionSuggestions/Entry/Entry';
// mention suggestion component
function Entry(props: EntryComponentProps): ReactElement {
const { mention, theme, searchValue, isFocused, ...parentProps } = props;
return (
<div {...parentProps}>
<div className={theme?.mentionSuggestionsEntryContainer}>
<div className={theme?.mentionSuggestionsEntryContainerLeft}>
<img
src={mention.avatar}
className={theme?.mentionSuggestionsEntryAvatar}
role='presentation'
/>
</div>
<div className={theme?.mentionSuggestionsEntryContainerRight}>
<div className={theme?.mentionSuggestionsEntryText}>{mention.name}</div>
<div className={theme?.mentionSuggestionsEntryTitle}>{mention.title}</div>
</div>
</div>
</div>
);
}
export default function DynamicPostInputArea({
editorKey = 'comment',
placeholder = 'Write a comment',
}) {
const ref = useRef<Editor>(null);
// editor state
const [editorState, setEditorState] = useState(EditorState.createEmpty());
const [open, setOpen] = useState(false);
const [suggestions, setSuggestions] = useState(mentions);
// =================================================================
// == set plugins & configuration settings for the dynamic post input area
// =================================================================
const { plugins, MentionSuggestions } = useMemo(() => {
// link detection plugin
const linkifyPlugin = createLinkifyPlugin({
customExtractLinks: (text) => linkifyIt().tlds(tlds).set({ fuzzyEmail: false }).match(text),
component(props) {
// eslint-disable-next-line no-alert, jsx-a11y/anchor-has-content
return <a style={{ color: 'var(--link)' }} {...props} />;
},
});
// hashtag detection plugin
const hashtagPlugin = createHashtagPlugin({
theme: hashtagStyles,
});
// mention detection plugin
const mentionPlugin = createMentionPlugin({
// entityMutability: 'IMMUTABLE',
supportWhitespace: true,
});
const { MentionSuggestions } = mentionPlugin;
const plugins = [hashtagPlugin, linkifyPlugin, mentionPlugin];
return { plugins, MentionSuggestions };
}, []);
// =================================================================
// == mention modifier
// =================================================================
const onOpenChange = useCallback((_open: boolean) => {
setOpen(_open);
}, []);
const onSearchChange = useCallback(({ value }: { value: string }) => {
setSuggestions(defaultSuggestionsFilter(value, mentions));
}, []);
// =================================================================
// == on change of editor inputs this function will be called
// =================================================================
const onChange = useCallback((_editorState: EditorState) => {
setEditorState(_editorState);
const contentState = _editorState.getCurrentContent();
const inputData = {
text: _editorState.getCurrentContent().getPlainText('\u0001'),
content: convertToRaw(contentState),
entityMap: contentState.getAllEntities(),
};
console.log(inputData);
}, []);
return (
<>
<div
className={editorStyles.editor}
onClick={() => {
ref.current!.focus();
}}>
<Editor
ref={ref}
placeholder={placeholder}
editorState={editorState}
editorKey={editorKey}
onChange={onChange}
// onChange={setEditorState}
plugins={plugins}
// decorators={}
// keyBindingFn={bindedKeys}
/>
<MentionSuggestions
open={open}
onOpenChange={onOpenChange}
suggestions={suggestions}
onSearchChange={onSearchChange}
// onAddMention={() => {
// // get the mention object selected
// }}
// entryComponent={Entry}
popoverContainer={({ children }) => <div>{children}</div>}
/>
</div>
<style jsx global>{`
.public-DraftEditorPlaceholder-root {
position: absolute;
}
.public-DraftEditorPlaceholder-root > * {
color: var(--outline);
font-size: 0.875rem;
}
`}</style>
</>
);
}
I need some data like this for every hashtags & URLs
...
entityRanges: [
{
offset: 7,
length: 14,
key: 2,
},
{
offset: 25,
length: 7,
key: 3,
}]
...
entityMap: {
'2': {
type: 'LINK',
mutability: 'MUTABLE',
data: {
href: 'http://helloworld.com/',
rel: 'noreferrer noopener',
target: '_self',
url: 'http://helloworld.com/',
},
},
'3': {
type: 'LINK',
mutability: 'MUTABLE',
data: {
href: 'http://abcd.co/',
rel: 'noreferrer noopener',
target: '_self',
url: 'http://abcd.co/',
},
},
}
...
If anyone can help me solve this it'll be a great help for me. Thank you.