UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

301 lines (298 loc) 13.9 kB
"use strict"; 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';