1

Using draft.js how you go about adding a custom link entity with meta data? Example of what I did: For one of my editor menu buttons I have added a click handler that creates an entity called 'META_WRAPPER':

 const handleMetaWrapperBtnClick = () => {

    const elementType = link ? 'MW_LINK' : 'MW_SPAN'

    const newEditorState = applyEntityWithData(editorState, 'META_WRAPPER', {
      elementType,
      id,
      url: link,
      text: text,
    })

    if (newEditorState) {
      setEditorState(newEditorState)
    }

    closeDialog()
  }

I have added a decorator strategy and component to handle the custom 'META_WRAPPER' entities added by the above handleMetaWrapperBtnClick :

Strategy to find 'META_WRAPPER'-

export const metaWrapperStrategy = (
  contentBlock: ContentBlock,
  callback: (a: any, b: any) => any,
  contentState: ContentState
) => {
  contentBlock.findEntityRanges((character) => {
    const entityKey = character.getEntity()
    return entityKey !== null && contentState.getEntity(entityKey).getType() === 'META_WRAPPER'
  }, callback)
}

Decorator Components to be rendered for the custom META_WRAPPER found by metaWrapperStrategy:

export const MetaWrapper: React.FC = (props: any) => {
  const { elementType } = props.contentState.getEntity(props.entityKey).getData()

  switch (elementType) {
    case 'MW_LINK':
      return <MwLink {...props} />
    default:
      //MW_SPAN
      return <MwSpan {...props} />
  }
}

const MwLink: React.FC = (props: any) => {
  const classes = useStyles()
  const { id, url, text } = props.contentState.getEntity(props.entityKey).getData()
  return (
    <a rel="nofollow noreferrer" id={id} href={url} className={classes.mwLink}>
      {text || props.children}
    </a>
  )
}

const MwSpan: React.FC = (props: any) => {
  const classes = useStyles()
  const { id, text } = props.contentState.getEntity(props.entityKey).getData()
  return (
    <span id={id} className={classes.mwSpan}>
      {text || props.children}
    </span>
  )
}

const customDecorators = [
    {
      strategy: metaWrapperStrategy,
      component: MetaWrapper,
    },
]

const compositeDecorator = new CompositeDecorator(customDecorators)

The above strangely works only locally and only when I put breakpoints and step through the code:

  1. Invocation of the handleMetaWrapperBtnClick handler which will result updating the editor state with the new custom entity,
  2. MetaWrapperStrategy runs
  3. MetaWrapper components renders as a result
  4. success - The selection is replaced with the custom MwSpan or MwLink inside the editor.(Either one of MwSpan or MwLink will render based on the value of the elementType meta field)

However when running the code without breakpoints nothing happens to the selection in the editor.

Also when it works it is not possible to add inline styles like bold text to the same selection.

I also created this CodeSanbox to demonstrate the issue: https://codesandbox.io/s/dry-river-qlysv?file=/src/Components/DraftEditor.js

Kamran
  • 819
  • 3
  • 14
  • 22

0 Answers0