Inline Video Embed Extension

I’m working on a video (iframe) embed extension to allow our users to embed Vimeo videos. I have a component working outside of Prosemirror (Remirror really) but am experiencing some strange behaviour now that I’ve built the extension:

My video embed extension is basically an input with some validation to ensure that the user is submitting a Vimeo link. If it’s valid, the input box is swapped out for an iframe that users the input value as the src.

I have three main issues. Could anyone help?

  1. If you paste, the pasted content is injected above the input node as text.
  2. If you type, the first character is injected above the input node.
  3. If you focus on the text input and hit backspace, the node is deleted if there is no content.

I came across this article (Embedding a video player in the editor) but there’s nothing obvious in there that would help me solve the problems listed above.

Here you can see what happens when I paste a valid Vimeo link into my input. It is injected into my content and then a separate “link preview” extension unfurls it.

My extension currently looks like this:

import React from 'react';
import { NodeExtension, ExtensionTag, isElementDomNode } from 'remirror';
import { getNodeSpecAttributes, createDomAttributes, parseVideoAttributes } from './utils';
import VideoWrapper from './VideoWrapper';

class BenefexVideoExtension extends NodeExtension {
  tags = [ExtensionTag.BlockNode];

  get name() {
    return 'video';
  }

  createNodeSpec(extra) {
    return {
      atom: true,
      leaf: false,
      code: true,
      selectable: false,
      attrs: {
        ...extra.defaults(),
        ...getNodeSpecAttributes(),
      },
      parseDOM: [
        {
          tag: 'video',
          getAttrs: (element) =>
            isElementDomNode(element)
              ? parseVideoAttributes({
                  element,
                  parse: extra.parse,
                })
              : {},
        },
      ],
      toDOM: (node) => {
        const attrs = createDomAttributes(node.attrs);
        return ['iframe', { ...extra.dom(node), ...attrs }, ''];
      },
    };
  }

  createCommands() {
    return {
      insertBenefexVideo:
        (attrs = {}) =>
        ({ dispatch, tr }) => {
          const node = this.type.create(attrs);

          if (dispatch) {
            dispatch(tr.replaceSelectionWith(node).scrollIntoView());
          }

          return true;
        },
    };
  }

  ReactComponent = ({ node }) => <VideoWrapper />;
}

export default BenefexVideoExtension;

Assuming this is a widget decoration or node view that sits inside the editor, defining a stopEvent method to prevent the editor from handling events inside the control might help here.

Thanks, where and how would I go about defining them? :slight_smile: