Search code examples
reactjsfunctional-programmingdraftjsdraft-js-plugins

Draft.js adding hyperlink using applyEntity doesn't seem to work


I've been working on this problem for a while, and I hope it's not a bug.

I'm testing a text editor using Draft.js, and I'd simply like my users to add a hyperlink to their articles, so I create a function for that to happen by modifying the editor state's content.

const addLlink = (e) => {
    e.preventDefault();
    const contentState = editorState.getCurrentContent();
    const contentStateWithEntity = contentState.createEntity(
        'LINK', 'MUTABLE', {url: 'https://www.amazon.com'} // link for testing only
    );
    const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
    const contentStateWithLink = Modifier.applyEntity(
        contentStateWithEntity,
        editorState.getSelection(),
        entityKey
    );
    // tried with and without styling
    const styledContentStateWithLink = Modifier.applyInlineStyle(
        contentStateWithLink,
        editorState.getSelection(),
        'HYPERLINK'
    );
    const newState = EditorState.set(editorState, {
        currentContent: styledContentStateWithLink
    });

    setEditorState(newState);
    // Also tried: setEditorState(RichUtils.toggleLink(newState, newState.getSelection(), entityKey));
}

When I trigger it, I just use an Evergreen-ui button:

<Button onMouseDown={addLlink} appearance="minimal">Link</Button>

The styling I implement using the Modifier object works, but I can't seem to get the link to actually work. It should be noted that the link plugin as a package, which works great, but that's only for detecting typed out/pasted URLs (not embedded into text).

Does anyone have an actual working example, or suggestions of what I may be doing wrong, for links that use React functional programming?


Solution

  • It turns out that I needed to add a Decorator in order for the entity to be detected. I placed this code above/outside of my Editor component:

    const findLinkEntities = (contentBlock, callback, contentState) => {
    contentBlock.findEntityRanges(
      (character) => {
        const entityKey = character.getEntity();
        return (
          entityKey !== null &&
          contentState.getEntity(entityKey).getType() === 'LINK'
        );
      },
      callback
    );
    
    
    }
    const Link = (props) => {
        const {url} = props.contentState.getEntity(props.entityKey).getData();
        return (
          <a href={url} >
            {props.children}
          </a>
        );
    };
    
    const strategyDecorator = new CompositeDecorator([
        {
          strategy: findLinkEntities,
          component: Link,
        },
    ]);
    

    Basically, it detects link entities and converts them into elements when you set the new content using EditorState:

    const newState = EditorState.set(editorState, {
            currentContent: styledContentStateWithLink,
            decorator: strategyDecorator
        });