UNPKG

@atlaskit/editor-plugin-card

Version:

Card plugin for @atlaskit/editor-core

302 lines (297 loc) 14.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.blockCardNodeView = exports.BlockCardComponent = exports.BlockCard = void 0; var _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var _rafSchd = _interopRequireDefault(require("raf-schd")); var _v = _interopRequireDefault(require("uuid/v4")); var _browser = require("@atlaskit/editor-common/browser"); var _reactNodeView = _interopRequireDefault(require("@atlaskit/editor-common/react-node-view")); var _ui = require("@atlaskit/editor-common/ui"); var _utils = require("@atlaskit/editor-common/utils"); var _editorSmartLinkDraggable = require("@atlaskit/editor-smart-link-draggable"); var _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); var _smartCard = require("@atlaskit/smart-card"); var _ssr = require("@atlaskit/smart-card/ssr"); var _datasource = require("../nodeviews/datasource"); var _actions = require("../pm-plugins/actions"); var _utils2 = require("../pm-plugins/utils"); var _genericCard = require("./genericCard"); function _superPropGet(t, o, e, r) { var p = (0, _get2.default)((0, _getPrototypeOf2.default)(1 & r ? t.prototype : t), o, e); return 2 & r && "function" == typeof p ? function (t) { return p.apply(e, t); } : p; } function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead // eslint-disable-next-line @repo/internal/react/no-class-components var BlockCardComponent = exports.BlockCardComponent = /*#__PURE__*/function (_React$PureComponent) { function BlockCardComponent(props) { var _this; (0, _classCallCheck2.default)(this, BlockCardComponent); _this = _callSuper(this, BlockCardComponent, [props]); // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting (0, _defineProperty2.default)(_this, "onResolve", function (data) { var _this$props = _this.props, getPos = _this$props.getPos, view = _this$props.view; if (!getPos || typeof getPos === 'boolean') { return; } var title = data.title, url = data.url; // don't dispatch immediately since we might be in the middle of // rendering a nodeview (0, _rafSchd.default)(function () { var pos = getPos(); if (typeof pos !== 'number') { return; } view.dispatch((0, _actions.registerCard)({ title: title, url: url, pos: pos, id: _this.props.id })(view.state.tr)); })(); }); (0, _defineProperty2.default)(_this, "removeCardDispatched", false); (0, _defineProperty2.default)(_this, "gapCursorSpan", function () { var browser = (0, _browser.getBrowserInfo)(); // Don't render in EdgeHTMl version <= 18 (Edge version 44) // as it forces the edit popup to render 24px lower than it should if (browser.ie && browser.ie_version < 79) { return; } // render an empty span afterwards to get around Webkit bug // that puts caret in next editable text element return /*#__PURE__*/_react.default.createElement("span", { contentEditable: true }); }); (0, _defineProperty2.default)(_this, "onError", function (_ref) { var err = _ref.err; if (err) { throw err; } }); _this.scrollContainer = (0, _ui.findOverflowScrollParent)(props.view.dom) || undefined; return _this; } (0, _inherits2.default)(BlockCardComponent, _React$PureComponent); return (0, _createClass2.default)(BlockCardComponent, [{ key: "componentWillUnmount", value: function componentWillUnmount() { this.removeCard(); } }, { key: "removeCard", value: function removeCard() { if (this.removeCardDispatched) { return; } this.removeCardDispatched = true; var tr = this.props.view.state.tr; (0, _actions.removeCard)({ id: this.props.id })(tr); this.props.view.dispatch(tr); } }, { key: "render", value: function render() { var _this$props2 = this.props, node = _this$props2.node, cardContext = _this$props2.cardContext, actionOptions = _this$props2.actionOptions, onClick = _this$props2.onClick, CompetitorPrompt = _this$props2.CompetitorPrompt, isPageSSRed = _this$props2.isPageSSRed; var _node$attrs = node.attrs, url = _node$attrs.url, data = _node$attrs.data; var cardInner = isPageSSRed ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_ssr.CardSSR, { key: url, url: url !== null && url !== void 0 ? url : data.url, container: this.scrollContainer, appearance: "block", onClick: onClick, onResolve: this.onResolve, onError: this.onError, platform: 'web', actionOptions: actionOptions, CompetitorPrompt: CompetitorPrompt, hideIconLoadingSkeleton: true }), this.gapCursorSpan()) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_smartCard.Card, { key: url, url: url !== null && url !== void 0 ? url : data.url, container: this.scrollContainer, appearance: "block", onClick: onClick, onResolve: this.onResolve, onError: this.onError, platform: 'web', actionOptions: actionOptions, CompetitorPrompt: CompetitorPrompt }), this.gapCursorSpan()); // [WS-2307]: we only render card wrapped into a Provider when the value is ready, // otherwise if we got data, we can render the card directly since it doesn't need the Provider return /*#__PURE__*/_react.default.createElement(_editorSmartLinkDraggable.SmartLinkDraggable, { url: url, appearance: _editorSmartLinkDraggable.SMART_LINK_APPEARANCE.BLOCK, source: _editorSmartLinkDraggable.SMART_LINK_DRAG_TYPES.EDITOR }, /*#__PURE__*/_react.default.createElement("div", null, cardContext && cardContext.value ? /*#__PURE__*/_react.default.createElement(cardContext.Provider, { value: cardContext.value }, cardInner) : data ? cardInner : null)); } }]); }(_react.default.PureComponent); var WrappedBlockCard = (0, _genericCard.Card)(BlockCardComponent, _ui.UnsupportedBlock); var BlockCard = exports.BlockCard = /*#__PURE__*/function (_ReactNodeView) { function BlockCard() { var _this2; (0, _classCallCheck2.default)(this, BlockCard); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this2 = _callSuper(this, BlockCard, [].concat(args)); // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead (0, _defineProperty2.default)(_this2, "id", (0, _v.default)()); (0, _defineProperty2.default)(_this2, "updateContentEditable", function (editorViewModeState, divElement) { divElement.contentEditable = (editorViewModeState === null || editorViewModeState === void 0 ? void 0 : editorViewModeState.mode) === 'view' ? 'false' : 'true'; }); return _this2; } (0, _inherits2.default)(BlockCard, _ReactNodeView); return (0, _createClass2.default)(BlockCard, [{ key: "createDomRef", value: function createDomRef() { var _this$reactComponentP, _this3 = this, _this$reactComponentP2; var domRef = document.createElement('div'); // workaround Chrome bug in https://product-fabric.atlassian.net/browse/ED-5379 // see also: https://github.com/ProseMirror/prosemirror/issues/884 this.unsubscribe = (_this$reactComponentP = this.reactComponentProps.pluginInjectionApi) === null || _this$reactComponentP === void 0 || (_this$reactComponentP = _this$reactComponentP.editorViewMode) === null || _this$reactComponentP === void 0 ? void 0 : _this$reactComponentP.sharedState.onChange(function (_ref2) { var nextSharedState = _ref2.nextSharedState; return _this3.updateContentEditable(nextSharedState, domRef); }); this.updateContentEditable((_this$reactComponentP2 = this.reactComponentProps.pluginInjectionApi) === null || _this$reactComponentP2 === void 0 || (_this$reactComponentP2 = _this$reactComponentP2.editorViewMode) === null || _this$reactComponentP2 === void 0 ? void 0 : _this$reactComponentP2.sharedState.currentState(), domRef); domRef.setAttribute('spellcheck', 'false'); return domRef; } }, { key: "validUpdate", value: // Need this function to check if the datasource attribute was added or not to a blockCard. // If so, we return false so we can get the node to re-render properly as a datasource node instead. // Otherwise, the node view will still consider the node as a blockCard and render a regular blockCard. function validUpdate(currentNode, newNode) { var isCurrentNodeBlockCard = !(0, _utils2.isDatasourceNode)(currentNode); var isNewNodeDatasource = (0, _utils2.isDatasourceNode)(newNode); // need to return falsy to update node return !(isCurrentNodeBlockCard && isNewNodeDatasource); } }, { key: "update", value: function update(node, decorations, _innerDecorations) { return _superPropGet(BlockCard, "update", this, 3)([node, decorations, _innerDecorations, this.validUpdate]); } }, { key: "render", value: function render() { var _this$reactComponentP3 = this.reactComponentProps, actionOptions = _this$reactComponentP3.actionOptions, pluginInjectionApi = _this$reactComponentP3.pluginInjectionApi, onClickCallback = _this$reactComponentP3.onClickCallback, CompetitorPrompt = _this$reactComponentP3.CompetitorPrompt, isPageSSRed = _this$reactComponentP3.isPageSSRed, provider = _this$reactComponentP3.provider; return /*#__PURE__*/_react.default.createElement(WrappedBlockCard, { node: this.node, view: this.view, getPos: this.getPos, actionOptions: actionOptions, pluginInjectionApi: pluginInjectionApi, onClickCallback: onClickCallback, id: this.id, CompetitorPrompt: CompetitorPrompt, isPageSSRed: isPageSSRed, provider: provider }); } /** * Prevent ProseMirror from handling drag events on the smart-element-link, * allowing native drag to work so SmartLinkDraggable can intercept it. * @see {@link https://prosemirror.net/docs/ref/#view.NodeView.stopEvent} */ }, { key: "stopEvent", value: function stopEvent(event) { if (event.type === 'dragstart') { var target = event.target; if (target instanceof HTMLElement && target.closest('[data-smart-element-link]') && (0, _platformFeatureFlags.fg)('cc_drag_and_drop_smart_link_from_content_to_tree')) { return true; } } return false; } }, { key: "destroy", value: function destroy() { var _this$unsubscribe; (_this$unsubscribe = this.unsubscribe) === null || _this$unsubscribe === void 0 || _this$unsubscribe.call(this); _superPropGet(BlockCard, "destroy", this, 3)([]); } }]); }(_reactNodeView.default); var blockCardNodeView = exports.blockCardNodeView = function blockCardNodeView(_ref3) { var pmPluginFactoryParams = _ref3.pmPluginFactoryParams, actionOptions = _ref3.actionOptions, pluginInjectionApi = _ref3.pluginInjectionApi, onClickCallback = _ref3.onClickCallback, allowDatasource = _ref3.allowDatasource, inlineCardViewProducer = _ref3.inlineCardViewProducer, CompetitorPrompt = _ref3.CompetitorPrompt, isPageSSRed = _ref3.isPageSSRed, provider = _ref3.provider; return function (node, view, getPos, decorations) { var portalProviderAPI = pmPluginFactoryParams.portalProviderAPI, eventDispatcher = pmPluginFactoryParams.eventDispatcher; var reactComponentProps = { actionOptions: actionOptions, pluginInjectionApi: pluginInjectionApi, onClickCallback: onClickCallback, CompetitorPrompt: CompetitorPrompt, isPageSSRed: isPageSSRed, provider: provider }; var isDatasource = (0, _utils2.isDatasourceNode)(node); if (isDatasource) { var _node$attrs2; if (allowDatasource && (0, _utils.canRenderDatasource)(node === null || node === void 0 || (_node$attrs2 = node.attrs) === null || _node$attrs2 === void 0 || (_node$attrs2 = _node$attrs2.datasource) === null || _node$attrs2 === void 0 ? void 0 : _node$attrs2.id)) { var datasourcePosition = typeof getPos === 'function' && getPos(); var datasourceResolvedPosition = datasourcePosition && view.state.doc.resolve(datasourcePosition); var isNodeNested = !!(datasourceResolvedPosition && datasourceResolvedPosition.depth > 0); return new _datasource.Datasource({ node: node, view: view, getPos: getPos, portalProviderAPI: portalProviderAPI, eventDispatcher: eventDispatcher, pluginInjectionApi: pluginInjectionApi, isNodeNested: isNodeNested }).init(); } else { return inlineCardViewProducer(node, view, getPos, decorations); } } return new BlockCard(node, view, getPos, portalProviderAPI, eventDispatcher, reactComponentProps, undefined).init(); }; };