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?
- If you paste, the pasted content is injected above the input node as text.
- If you type, the first character is injected above the input node.
- 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;