@atlaskit/editor-plugin-card
Version:
Card plugin for @atlaskit/editor-core
302 lines (297 loc) • 14.7 kB
JavaScript
"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();
};
};