@atlaskit/editor-plugin-media
Version:
Media plugin for @atlaskit/editor-core
301 lines (298 loc) • 13.9 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.MediaGroupNext = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireWildcard(require("react"));
var _reactIntl = require("react-intl");
var _hooks = require("@atlaskit/editor-common/hooks");
var _media = require("@atlaskit/editor-common/media");
var _utils = require("@atlaskit/editor-common/utils");
var _cross = _interopRequireDefault(require("@atlaskit/icon/core/cross"));
var _mediaCommon = require("@atlaskit/media-common");
var _mediaFilmstrip = require("@atlaskit/media-filmstrip");
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
var _pluginKey = require("../pm-plugins/plugin-key");
var _mediaNodeUpdater = require("./mediaNodeUpdater");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var getIdentifier = function getIdentifier(item) {
if (item.attrs.type === 'external') {
return {
mediaItemType: 'external-image',
dataURI: item.attrs.url
};
}
return {
id: item.attrs.id,
mediaItemType: 'file',
collectionName: item.attrs.collection
};
};
var isNodeSelected = function isNodeSelected(props) {
return function (mediaItemPos, mediaGroupPos) {
var selected = (0, _utils.isNodeSelectedOrInRange)(props.anchorPos, props.headPos, mediaGroupPos, props.nodeSize);
if (selected === _utils.SelectedState.selectedInRange) {
return true;
}
if (selected === _utils.SelectedState.selectedInside && props.anchorPos === mediaItemPos) {
return true;
}
return false;
};
};
var prepareFilmstripItem = function prepareFilmstripItem(_ref) {
var allowLazyLoading = _ref.allowLazyLoading,
allowMediaInlineImages = _ref.allowMediaInlineImages,
enableDownloadButton = _ref.enableDownloadButton,
handleMediaNodeRemoval = _ref.handleMediaNodeRemoval,
getPos = _ref.getPos,
intl = _ref.intl,
isMediaItemSelected = _ref.isMediaItemSelected,
setMediaGroupNodeSelection = _ref.setMediaGroupNodeSelection,
featureFlags = _ref.featureFlags;
return function (item, idx) {
// We declared this to get a fresh position every time
var getNodePos = function getNodePos() {
var pos = getPos();
if (typeof pos !== 'number') {
// That may seems weird, but the previous type wasn't match with the real ProseMirror code. And a lot of Media API was built expecting a number
// Because the original code would return NaN on runtime
// We are just make it explict now.
// We may run a deep investagation on Media code to figure out a better fix. But, for now, we want to keep the current behavior.
// TODO: ED-13910 - prosemirror-bump leftovers
return NaN;
}
return pos + idx + 1;
};
// Media Inline creates a floating toolbar with the same options, excludes these options if enabled
var mediaInlineOptions = function mediaInlineOptions() {
var allowMediaInline = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
if (!allowMediaInline) {
return {
shouldEnableDownloadButton: enableDownloadButton,
actions: [{
handler: handleMediaNodeRemoval.bind(null, undefined, getNodePos),
icon: /*#__PURE__*/_react.default.createElement(_cross.default, {
label: intl.formatMessage(_media.nodeViewsMessages.mediaGroupDeleteLabel)
})
}]
};
}
};
var mediaGroupPos = getPos();
return _objectSpread({
identifier: getIdentifier(item),
isLazy: allowLazyLoading,
selected: isMediaItemSelected(getNodePos(), typeof mediaGroupPos === 'number' ? mediaGroupPos : NaN),
onClick: function onClick() {
setMediaGroupNodeSelection(getNodePos());
}
}, mediaInlineOptions((0, _platformFeatureFlags.fg)('platform_editor_remove_media_inline_feature_flag') ? allowMediaInlineImages : (0, _mediaCommon.getMediaFeatureFlag)('mediaInline', featureFlags)));
};
};
/**
* Keep returning the same ProseMirror Node, unless the node content changed.
*
* React uses shallow comparation with `Object.is`,
* but that can cause multiple re-renders when the same node is given in a different instance.
*
* To avoid unnecessary re-renders, this hook uses the `Node.eq` from ProseMirror API to compare
* previous and new values.
*/
var useLatestMediaGroupNode = function useLatestMediaGroupNode(nextMediaNode) {
var previousMediaNode = (0, _hooks.usePreviousState)(nextMediaNode);
var _React$useState = _react.default.useState(nextMediaNode),
_React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
mediaNode = _React$useState2[0],
setMediaNode = _React$useState2[1];
_react.default.useEffect(function () {
if (!previousMediaNode) {
return;
}
if (!previousMediaNode.eq(nextMediaNode)) {
setMediaNode(nextMediaNode);
}
}, [previousMediaNode, nextMediaNode]);
return mediaNode;
};
var runMediaNodeUpdate = /*#__PURE__*/function () {
var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(_ref2) {
var mediaNodeUpdater, getPos, node, updateAttrs, contextId, shouldNodeBeDeepCopied;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
mediaNodeUpdater = _ref2.mediaNodeUpdater, getPos = _ref2.getPos, node = _ref2.node, updateAttrs = _ref2.updateAttrs;
if (!updateAttrs) {
_context.next = 4;
break;
}
_context.next = 4;
return mediaNodeUpdater.updateNodeAttrs(getPos);
case 4:
contextId = mediaNodeUpdater.getNodeContextId();
if (contextId) {
_context.next = 8;
break;
}
_context.next = 8;
return mediaNodeUpdater.updateNodeContextId(getPos);
case 8:
_context.next = 10;
return mediaNodeUpdater.shouldNodeBeDeepCopied();
case 10:
shouldNodeBeDeepCopied = _context.sent;
if (!shouldNodeBeDeepCopied) {
_context.next = 14;
break;
}
_context.next = 14;
return mediaNodeUpdater.copyNodeFromPos(getPos, {
traceId: node.attrs.__mediaTraceId
});
case 14:
case "end":
return _context.stop();
}
}, _callee);
}));
return function runMediaNodeUpdate(_x) {
return _ref3.apply(this, arguments);
};
}();
var noop = function noop() {};
// eslint-disable-next-line @typescript-eslint/ban-types
var MediaGroupNext = exports.MediaGroupNext = (0, _reactIntl.injectIntl)( /*#__PURE__*/_react.default.memo(function (props) {
var _props$mediaOptions = props.mediaOptions,
allowLazyLoading = _props$mediaOptions.allowLazyLoading,
allowMediaInlineImages = _props$mediaOptions.allowMediaInlineImages,
enableDownloadButton = _props$mediaOptions.enableDownloadButton,
featureFlags = _props$mediaOptions.featureFlags,
intl = props.intl,
_getPos = props.getPos,
anchorPos = props.anchorPos,
headPos = props.headPos,
view = props.view,
disabled = props.disabled,
editorViewMode = props.editorViewMode,
mediaProvider = props.mediaProvider,
contextIdentifierProvider = props.contextIdentifierProvider,
isCopyPasteEnabled = props.isCopyPasteEnabled;
var mediaGroupNode = useLatestMediaGroupNode(props.node);
var mediaPluginState = (0, _react.useMemo)(function () {
return _pluginKey.stateKey.getState(view.state);
}, [view.state]);
var mediaClientConfig = mediaPluginState === null || mediaPluginState === void 0 ? void 0 : mediaPluginState.mediaClientConfig;
var handleMediaGroupUpdate = mediaPluginState === null || mediaPluginState === void 0 ? void 0 : mediaPluginState.handleMediaGroupUpdate;
var _useState = (0, _react.useState)(undefined),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
viewMediaClientConfig = _useState2[0],
setViewMediaClientConfig = _useState2[1];
var nodeSize = mediaGroupNode.nodeSize;
var mediaNodesWithOffsets = (0, _react.useMemo)(function () {
var result = [];
mediaGroupNode.forEach(function (item, childOffset) {
result.push({
node: item,
offset: childOffset
});
});
return result;
}, [mediaGroupNode]);
var previousMediaNodesWithOffsets = (0, _hooks.usePreviousState)(mediaNodesWithOffsets);
var handleMediaNodeRemoval = (0, _react.useMemo)(function () {
return disabled || !mediaPluginState ? noop : mediaPluginState.handleMediaNodeRemoval;
}, [disabled, mediaPluginState]);
var setMediaGroupNodeSelection = (0, _react.useCallback)(function (pos) {
(0, _utils.setNodeSelection)(view, pos);
}, [view]);
var isMediaItemSelected = (0, _react.useMemo)(function () {
return isNodeSelected({
anchorPos: anchorPos,
headPos: headPos,
nodeSize: nodeSize
});
}, [anchorPos, headPos, nodeSize]);
var filmstripItem = (0, _react.useMemo)(function () {
return prepareFilmstripItem({
allowLazyLoading: allowLazyLoading,
allowMediaInlineImages: allowMediaInlineImages,
enableDownloadButton: enableDownloadButton,
handleMediaNodeRemoval: handleMediaNodeRemoval,
getPos: _getPos,
intl: intl,
isMediaItemSelected: isMediaItemSelected,
setMediaGroupNodeSelection: setMediaGroupNodeSelection,
featureFlags: featureFlags
});
}, [allowLazyLoading, allowMediaInlineImages, enableDownloadButton, handleMediaNodeRemoval, _getPos, intl, isMediaItemSelected, setMediaGroupNodeSelection, featureFlags]);
var items = (0, _react.useMemo)(function () {
return mediaNodesWithOffsets.map(function (_ref4) {
var node = _ref4.node,
offset = _ref4.offset;
return filmstripItem(node, offset);
});
}, [mediaNodesWithOffsets, filmstripItem]);
(0, _react.useEffect)(function () {
setViewMediaClientConfig(mediaClientConfig);
}, [mediaClientConfig]);
(0, _react.useEffect)(function () {
// eslint-disable-next-line @atlassian/perf-linting/no-chain-state-updates -- Ignored via go/ees017 (to be fixed)
mediaNodesWithOffsets.forEach(function (_ref5) {
var node = _ref5.node,
offset = _ref5.offset;
var mediaNodeUpdater = (0, _mediaNodeUpdater.createMediaNodeUpdater)({
view: view,
mediaProvider: mediaProvider,
contextIdentifierProvider: contextIdentifierProvider,
node: node,
isMediaSingle: false
});
var updateAttrs = isCopyPasteEnabled || isCopyPasteEnabled === undefined;
runMediaNodeUpdate({
mediaNodeUpdater: mediaNodeUpdater,
node: node,
updateAttrs: updateAttrs,
getPos: function getPos() {
var pos = _getPos();
if (typeof pos !== 'number') {
return undefined;
}
return pos + offset + 1;
}
});
});
}, [view, contextIdentifierProvider, _getPos, mediaProvider, mediaNodesWithOffsets, isCopyPasteEnabled]);
(0, _react.useEffect)(function () {
if (!handleMediaGroupUpdate || !previousMediaNodesWithOffsets) {
return;
}
var old = previousMediaNodesWithOffsets.map(function (_ref6) {
var node = _ref6.node;
return node;
});
var next = mediaNodesWithOffsets.map(function (_ref7) {
var node = _ref7.node;
return node;
});
handleMediaGroupUpdate(old, next);
return function () {
handleMediaGroupUpdate(next, []);
};
}, [handleMediaGroupUpdate, mediaNodesWithOffsets, previousMediaNodesWithOffsets]);
return /*#__PURE__*/_react.default.createElement(_mediaFilmstrip.Filmstrip, {
items: items,
mediaClientConfig: viewMediaClientConfig,
featureFlags: featureFlags,
shouldOpenMediaViewer: editorViewMode && (0, _experiments.editorExperiment)('platform_editor_controls', 'control')
});
}));
MediaGroupNext.displayName = 'MediaGroup';