UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

276 lines (275 loc) 12.1 kB
import React from 'react'; import { media, mediaGroup, mediaInline, mediaSingleSpec } from '@atlaskit/adf-schema'; import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics'; import { useSharedPluginState } from '@atlaskit/editor-common/hooks'; import { toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages'; import { IconImages } from '@atlaskit/editor-common/quick-insert'; import { SafePlugin } from '@atlaskit/editor-common/safe-plugin'; import { NodeSelection, PluginKey } from '@atlaskit/editor-prosemirror/state'; import { getMediaFeatureFlag } from '@atlaskit/media-common'; import { getBooleanFF } from '@atlaskit/platform-feature-flags'; import { ReactMediaGroupNode } from './nodeviews/mediaGroup'; import { ReactMediaInlineNode } from './nodeviews/mediaInline'; import { ReactMediaNode } from './nodeviews/mediaNodeView'; import { ReactMediaSingleNode } from './nodeviews/mediaSingle'; import { createPlugin as createMediaAltTextPlugin } from './pm-plugins/alt-text'; import keymapMediaAltTextPlugin from './pm-plugins/alt-text/keymap'; import keymapPlugin from './pm-plugins/keymap'; import keymapMediaSinglePlugin from './pm-plugins/keymap-media-single'; import linkingPlugin from './pm-plugins/linking'; import keymapLinkingPlugin from './pm-plugins/linking/keymap'; import { stateKey } from './pm-plugins/main'; import { createPlugin, stateKey as pluginKey } from './pm-plugins/main'; import { floatingToolbar as _floatingToolbar } from './toolbar'; import { MediaPickerComponents } from './ui/MediaPicker'; import ToolbarMedia from './ui/ToolbarMedia'; import { insertMediaAsMediaSingle as _insertMediaAsMediaSingle } from './utils/media-single'; export { insertMediaSingleNode } from './utils/media-single'; var MediaPickerFunctionalComponent = function MediaPickerFunctionalComponent(_ref) { var api = _ref.api, editorDomElement = _ref.editorDomElement, appearance = _ref.appearance; var _useSharedPluginState = useSharedPluginState(api, ['media']), mediaState = _useSharedPluginState.mediaState; if (!mediaState) { return null; } return /*#__PURE__*/React.createElement(MediaPickerComponents, { editorDomElement: editorDomElement, mediaState: mediaState, appearance: appearance, api: api }); }; export var mediaPlugin = function mediaPlugin(_ref2) { var _api$featureFlags; var _ref2$config = _ref2.config, options = _ref2$config === void 0 ? {} : _ref2$config, api = _ref2.api; var featureFlags = (api === null || api === void 0 || (_api$featureFlags = api.featureFlags) === null || _api$featureFlags === void 0 ? void 0 : _api$featureFlags.sharedState.currentState()) || {}; return { name: 'media', getSharedState: function getSharedState(editorState) { if (!editorState) { return null; } return stateKey.getState(editorState) || null; }, actions: { insertMediaAsMediaSingle: function insertMediaAsMediaSingle(view, node, inputMethod) { var _api$analytics; return _insertMediaAsMediaSingle(view, node, inputMethod, api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions); } }, nodes: function nodes() { var _ref3 = options || {}, _ref3$allowMediaGroup = _ref3.allowMediaGroup, allowMediaGroup = _ref3$allowMediaGroup === void 0 ? true : _ref3$allowMediaGroup, _ref3$allowMediaSingl = _ref3.allowMediaSingle, allowMediaSingle = _ref3$allowMediaSingl === void 0 ? false : _ref3$allowMediaSingl, allowCaptions = _ref3.allowCaptions, mediaFeatureFlags = _ref3.featureFlags; var allowMediaInline = getMediaFeatureFlag('mediaInline', mediaFeatureFlags); var mediaSingleOption = getBooleanFF('platform.editor.media.extended-resize-experience') ? { withCaption: allowCaptions, withExtendedWidthTypes: true } : { withCaption: allowCaptions, withExtendedWidthTypes: false }; var mediaSingleNode = mediaSingleSpec(mediaSingleOption); return [{ name: 'mediaGroup', node: mediaGroup }, { name: 'mediaSingle', node: mediaSingleNode }, { name: 'media', node: media }, { name: 'mediaInline', node: mediaInline }].filter(function (node) { if (node.name === 'mediaGroup') { return allowMediaGroup; } if (node.name === 'mediaSingle') { return allowMediaSingle; } if (node.name === 'mediaInline') { return allowMediaInline; } return true; }); }, pmPlugins: function pmPlugins() { var pmPlugins = [{ name: 'media', plugin: function plugin(_ref4) { var schema = _ref4.schema, dispatch = _ref4.dispatch, getIntl = _ref4.getIntl, eventDispatcher = _ref4.eventDispatcher, providerFactory = _ref4.providerFactory, errorReporter = _ref4.errorReporter, portalProviderAPI = _ref4.portalProviderAPI, reactContext = _ref4.reactContext, dispatchAnalyticsEvent = _ref4.dispatchAnalyticsEvent; return createPlugin(schema, { providerFactory: providerFactory, nodeViews: { mediaGroup: ReactMediaGroupNode(portalProviderAPI, eventDispatcher, providerFactory, options, api), mediaSingle: ReactMediaSingleNode(portalProviderAPI, eventDispatcher, providerFactory, api, dispatchAnalyticsEvent, options), media: ReactMediaNode(portalProviderAPI, eventDispatcher, providerFactory, options, api), mediaInline: ReactMediaInlineNode(portalProviderAPI, eventDispatcher, providerFactory, api) }, errorReporter: errorReporter, uploadErrorHandler: options && options.uploadErrorHandler, waitForMediaUpload: options && options.waitForMediaUpload, customDropzoneContainer: options && options.customDropzoneContainer, customMediaPicker: options && options.customMediaPicker, allowResizing: !!(options && options.allowResizing) }, reactContext, getIntl, api, dispatch, options, featureFlags.newInsertionBehaviour); } }, { name: 'mediaKeymap', plugin: function plugin() { var _api$analytics2; return keymapPlugin(options, api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions, api === null || api === void 0 ? void 0 : api.selection.actions); } }]; if (options && options.allowMediaSingle) { pmPlugins.push({ name: 'mediaSingleKeymap', plugin: function plugin(_ref5) { var schema = _ref5.schema; return keymapMediaSinglePlugin(schema); } }); } if (options && options.allowAltTextOnImages) { pmPlugins.push({ name: 'mediaAltText', plugin: createMediaAltTextPlugin }); pmPlugins.push({ name: 'mediaAltTextKeymap', plugin: function plugin(_ref6) { var _api$analytics3; var schema = _ref6.schema; return keymapMediaAltTextPlugin(schema, api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions); } }); } if (options && options.allowLinking) { pmPlugins.push({ name: 'mediaLinking', plugin: function plugin(_ref7) { var dispatch = _ref7.dispatch; return linkingPlugin(dispatch); } }); pmPlugins.push({ name: 'mediaLinkingKeymap', plugin: function plugin(_ref8) { var schema = _ref8.schema; return keymapLinkingPlugin(schema); } }); } pmPlugins.push({ name: 'mediaSelectionHandler', plugin: function plugin() { var mediaSelectionHandlerPlugin = new SafePlugin({ key: new PluginKey('mediaSelectionHandlerPlugin'), props: { handleScrollToSelection: function handleScrollToSelection(view) { var selection = view.state.selection; if (!(selection instanceof NodeSelection) || selection.node.type.name !== 'media') { return false; } var _view$domAtPos = view.domAtPos(selection.from), node = _view$domAtPos.node, offset = _view$domAtPos.offset; if ( // Is the media element mounted already? offset === node.childNodes.length) { // Media is not ready, so stop the scroll request return true; } // Media is ready, keep the scrolling request return false; } } }); return mediaSelectionHandlerPlugin; } }); return pmPlugins; }, contentComponent: function contentComponent(_ref9) { var editorView = _ref9.editorView, appearance = _ref9.appearance; return /*#__PURE__*/React.createElement(MediaPickerFunctionalComponent, { editorDomElement: editorView.dom, appearance: appearance, api: api }); }, secondaryToolbarComponent: function secondaryToolbarComponent(_ref10) { var editorView = _ref10.editorView, eventDispatcher = _ref10.eventDispatcher, disabled = _ref10.disabled; return /*#__PURE__*/React.createElement(ToolbarMedia, { isDisabled: disabled, isReducedSpacing: true, api: api }); }, pluginsOptions: { quickInsert: function quickInsert(_ref11) { var formatMessage = _ref11.formatMessage; return [{ id: 'media', title: formatMessage(messages.mediaFiles), description: formatMessage(messages.mediaFilesDescription), priority: 400, keywords: ['attachment', 'gif', 'media', 'picture', 'image', 'video'], icon: function icon() { return /*#__PURE__*/React.createElement(IconImages, null); }, action: function action(insert, state) { var _api$analytics4; var pluginState = pluginKey.getState(state); pluginState === null || pluginState === void 0 || pluginState.showMediaPicker(); var tr = insert(''); api === null || api === void 0 || (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 || _api$analytics4.actions.attachAnalyticsEvent({ action: ACTION.OPENED, actionSubject: ACTION_SUBJECT.PICKER, actionSubjectId: ACTION_SUBJECT_ID.PICKER_CLOUD, attributes: { inputMethod: INPUT_METHOD.QUICK_INSERT }, eventType: EVENT_TYPE.UI })(tr); return tr; } }]; }, floatingToolbar: function floatingToolbar(state, intl, providerFactory) { return _floatingToolbar(state, intl, { providerFactory: providerFactory, allowMediaInline: options && getMediaFeatureFlag('mediaInline', options.featureFlags), allowResizing: options && options.allowResizing, allowResizingInTables: options && options.allowResizingInTables, allowLinking: options && options.allowLinking, allowAdvancedToolBarOptions: options && options.allowAdvancedToolBarOptions, allowAltTextOnImages: options && options.allowAltTextOnImages, altTextValidator: options && options.altTextValidator, fullWidthEnabled: options && options.fullWidthEnabled }, api); } } }; };