var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; import { jsx as _jsx } from "react/jsx-runtime"; var ReactNodeView = /** @class */ (function () { function ReactNodeView(node, editor, getPos, portalProviderAPI, eventDispatcher, options) { var _this = this; this.editor = editor; this.getPos = getPos; this.portalProviderAPI = portalProviderAPI; this.eventDispatcher = eventDispatcher; this.options = options; this.handleRef = function (node) { return _this._handleRef(node); }; this.node = node; } /** * This method exists to move initialization logic out of the constructor, * so object can be initialized properly before calling render first time. * * Example: * Instance properties get added to an object only after super call in * constructor, which leads to some methods being undefined during the * first render. */ ReactNodeView.prototype.init = function () { var _this = this; this.domRef = this.createDomRef(); // this.setDomAttrs(this.node, this.domRef); var _a = this.getContentDOM() || { dom: undefined, contentDOM: undefined, }, contentDOMWrapper = _a.dom, contentDOM = _a.contentDOM; if (this.domRef && contentDOMWrapper) { this.domRef.appendChild(contentDOMWrapper); this.contentDOM = contentDOM ? contentDOM : contentDOMWrapper; this.contentDOMWrapper = contentDOMWrapper || contentDOM; } // @see ED-3790 // something gets messed up during mutation processing inside of a // nodeView if DOM structure has nested plain "div"s, it doesn't see the // difference between them and it kills the nodeView this.domRef.classList.add("".concat(this.node.type.name, "-view-content-wrap")); this.renderReactComponent(function () { return _this.render(_this.options.props, _this.handleRef); }); return this; }; ReactNodeView.prototype.renderReactComponent = function (component) { if (!this.domRef || !component) { return; } this.portalProviderAPI.render(component, this.domRef); }; ReactNodeView.prototype.createDomRef = function () { if (this.options.wrapperFactory) return this.options.wrapperFactory(); if (!this.node.isInline) { return document.createElement("div"); } var htmlElement = document.createElement("span"); return htmlElement; }; ReactNodeView.prototype.getContentDOM = function () { var _a, _b; return (_b = (_a = this.options).contentDOMFactory) === null || _b === void 0 ? void 0 : _b.call(_a); }; ReactNodeView.prototype._handleRef = function (node) { var contentDOM = this.contentDOMWrapper || this.contentDOM; // move the contentDOM node inside the inner reference after rendering if (node && contentDOM && !node.contains(contentDOM)) { node.appendChild(contentDOM); } }; ReactNodeView.prototype.render = function (props, forwardRef) { var _this = this; if (props === void 0) { props = {}; } if (!this.options.component) return null; return (_jsx(this.options.component, __assign({}, props, { editor: this.editor, getPos: this.getPos, node: this.node, forwardRef: forwardRef, updateAttributes: function (attr) { return _this.updateAttributes(attr); } }))); }; ReactNodeView.prototype.updateAttributes = function (attributes) { var _this = this; this.editor.commands.command(function (_a) { var tr = _a.tr; if (typeof _this.getPos === "boolean") return false; var pos = _this.getPos(); tr.setNodeMarkup(pos, undefined, __assign(__assign({}, _this.node.attrs), attributes)); return true; }); }; ReactNodeView.prototype.update = function (node, _decorations, _innerDecorations // _innerDecorations?: Array, // validUpdate: (currentNode: PMNode, newNode: PMNode) => boolean = () => true ) { var _this = this; // @see https://github.com/ProseMirror/prosemirror/issues/648 var isValidUpdate = this.node.type === node.type; // && validUpdate(this.node, node); if (!isValidUpdate) { return false; } // if (this.domRef && !this.node.sameMarkup(node)) { // this.setDomAttrs(node, this.domRef); // } // View should not process a re-render if this is false. // We dont want to destroy the view, so we return true. if (!this.viewShouldUpdate(node)) { this.node = node; return true; } this.node = node; this.renderReactComponent(function () { return _this.render(_this.options.props, _this.handleRef); }); return true; }; ReactNodeView.prototype.ignoreMutation = function (mutation) { if (!this.dom || !this.contentDOM) { return true; } // TODO if (typeof this.options.ignoreMutation === 'function') { // return this.options.ignoreMutation({ mutation }) // } // a leaf/atom node is like a black box for ProseMirror // and should be fully handled by the node view if (this.node.isLeaf || this.node.isAtom) { return true; } // ProseMirror should handle any selections if (mutation.type === "selection") { return false; } // try to prevent a bug on mobiles that will break node views on enter // this is because ProseMirror can’t preventDispatch on enter // this will lead to a re-render of the node view on enter // see: https://github.com/ueberdosis/tiptap/issues/1214 if (this.dom.contains(mutation.target) && mutation.type === "childList" && this.editor.isFocused) { var changedNodes = __spreadArray(__spreadArray([], __read(Array.from(mutation.addedNodes)), false), __read(Array.from(mutation.removedNodes)), false); // we’ll check if every changed node is contentEditable // to make sure it’s probably mutated by ProseMirror if (changedNodes.every(function (node) { return node.isContentEditable; })) { return false; } } // we will allow mutation contentDOM with attributes // so we can for example adding classes within our node view if (this.contentDOM === mutation.target && mutation.type === "attributes") { return true; } // ProseMirror should handle any changes within contentDOM if (this.contentDOM.contains(mutation.target)) { return false; } return true; }; ReactNodeView.prototype.viewShouldUpdate = function (nextNode) { if (this.options.shouldUpdate) return this.options.shouldUpdate(this.node, nextNode); return true; }; /** * Copies the attributes from a ProseMirror Node to a DOM node. * @param node The Prosemirror Node from which to source the attributes */ ReactNodeView.prototype.setDomAttrs = function (node, element) { Object.keys(node.attrs || {}).forEach(function (attr) { element.setAttribute(attr, node.attrs[attr]); }); }; Object.defineProperty(ReactNodeView.prototype, "dom", { get: function () { return this.domRef; }, enumerable: false, configurable: true }); ReactNodeView.prototype.destroy = function () { if (!this.domRef) { return; } this.portalProviderAPI.remove(this.domRef); // @ts-ignore NEW PM API this.domRef = undefined; this.contentDOM = undefined; }; ReactNodeView.fromComponent = function (component, options) { return function (_a) { var node = _a.node, getPos = _a.getPos, editor = _a.editor; return new ReactNodeView(node, editor, getPos, editor.storage.portalProviderAPI, editor.storage.eventDispatcher, __assign(__assign({}, options), { component: component })).init(); }; }; return ReactNodeView; }()); export default ReactNodeView; function isiOS() { return ([ "iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod", ].includes(navigator.platform) || // iPad on iOS 13 detection (navigator.userAgent.includes("Mac") && "ontouchend" in document)); }