0

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.

Raybi
  • 1
  • 3

0 Answers0