Search code examples
javascriptreactjsdraftjs

How to create, style and defined data-attr's to a block in Draft-js?


Currently I have a DraftJS editor like this:

<Editor
  editorState={this.state.editorState}
  handleKeyCommand={this.handleKeyCommand}
  onChange={this.onChange}
  placeholder="Write a tweet..."
  ref="editor"
  spellCheck={true}
/>

The construcor with state:

constructor(props) {
  super(props);
  const compositeDecorator = new CompositeDecorator([{
    strategy: mentionStrategy,
    component: MentionSpan,
  }, {
    strategy: hashtagStrategy,
    component: HashtagSpan,
  }, {
    strategy: emojiStrategy,
    component: EmojiSpan,
  }]);

  this.state = {
    conversationActive: null,
    editorState: EditorState.createEmpty(compositeDecorator),
  };

  this.focus = () => this.refs.editor.focus();
  this.onChange = (editorState) => this.setState({editorState});
  this.logState = () => console.log(this.state.editorState.toJS());
  this.handleKeyCommand = () => 'not-handled';
}

I went as far as making a decorator strategy that matches a series of regex to figure out if a block is an emoji, like :D, :(, :|, etc.

The problem is that I can't figure out how to "pass more props" to the element in the strategy or how to create an entity from the match...

Here's the strategy:

const findWithRegex = (regex, contentBlock, callback) => {
  const text = contentBlock.getText();
  let matchArr, start;
  while ((matchArr = regex.exec(text)) !== null) {
    start = matchArr.index;
    callback(start, start + matchArr[0].length);
  }
}

const emojiRegexes = [...];

export const emojiStrategy = (contentBlock, callback, contentState) => {
  for (let i = 0; i < emojiRegexes.length; i++) {
    findWithRegex(emojiRegexes[i].regex, contentBlock, callback);
  }
}

export const EmojiSpan = (props) => {
  return (
    <span
      className={styles.emoji}
      data-offset-key={props.offsetKey}
    >
      {props.children}
    </span>
  );
};

Can anyone help me? Thanks!

PS: I can't seem to find a really in-depth documentation from draft-js the one on github only has shallow descriptions and dummy examples.


Solution

  • Managed to do what I wanted in a different manner, first, by replacing the text with unicode characters which in the future will be entities with metadata. The code is as follows:

    onChange(editorState) {
      const contentState = editorState.getCurrentContent();
      let currentText = contentState.getBlockForKey(editorState.getSelection().getAnchorKey()).getText();
    
      for (let i = 0; i < emojiRegexes.length; i++) {
        currentText = currentText.replace(emojiRegexes[i].regex, () => emojiRegexes[i].unicode)
      }
    
      if (currentText === contentState.getBlockForKey(editorState.getSelection().getAnchorKey()).getText()) {
        this.setState({ editorState });
        return;
      }
    
      const updatedSelection = editorState.getSelection().merge({
        anchorOffset: 0,
      });
    
      const edited = EditorState.push(
        editorState,
        Modifier.replaceText(
          contentState,
          updatedSelection,
          currentText
        ),
        'change-block-data'
      );
    
      this.setState({ editorState: edited });
    }