UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

396 lines (393 loc) 16.5 kB
import React from 'react'; import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics'; import commonMessages, { cardMessages, mediaAndEmbedToolbarMessages } from '@atlaskit/editor-common/messages'; import { areToolbarFlagsEnabled } from '@atlaskit/editor-common/toolbar-flag-check'; import { NodeSelection } from '@atlaskit/editor-prosemirror/state'; import DeleteIcon from '@atlaskit/icon/core/delete'; import DownloadIcon from '@atlaskit/icon/core/download'; import GrowDiagonalIcon from '@atlaskit/icon/core/grow-diagonal'; import ImageFullscreenIcon from '@atlaskit/icon/core/image-fullscreen'; import ImageInlineIcon from '@atlaskit/icon/core/image-inline'; import MaximizeIcon from '@atlaskit/icon/core/maximize'; import SmartLinkCardIcon from '@atlaskit/icon/core/smart-link-card'; import { messages } from '@atlaskit/media-ui'; import { showLinkingToolbar } from '../../pm-plugins/commands/linking'; import { getMediaLinkingState } from '../../pm-plugins/linking'; import { currentMediaOrInlineNodeBorderMark } from '../../pm-plugins/utils/current-media-node'; import { isImage } from '../../pm-plugins/utils/is-type'; import ImageBorderItem from '../../ui/ImageBorder'; import { altTextButton } from './alt-text'; import { changeInlineToMediaCard, changeMediaInlineToMediaSingle, removeInlineCardWithAnalytics, setBorderMark, toggleBorderMark } from './commands'; import { shouldShowImageBorder } from './imageBorder'; import { getOpenLinkToolbarButtonOption, shouldShowMediaLinkToolbar } from './linking'; import { LinkToolbarAppearance } from './linking-toolbar-appearance'; import { downloadMedia, getIsDownloadDisabledByDataSecurityPolicy, getMediaSingleAndMediaInlineSwitcherDropdown } from './utils'; import { handleShowMediaViewer } from './index'; export const generateMediaInlineFloatingToolbar = (state, intl, mediaPluginState, hoverDecoration, pluginInjectionApi, options = {}) => { var _pluginInjectionApi$a, _pluginInjectionApi$f, _pluginInjectionApi$f2; const editorAnalyticsAPI = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions; const forceFocusSelector = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$f = pluginInjectionApi.floatingToolbar) === null || _pluginInjectionApi$f === void 0 ? void 0 : (_pluginInjectionApi$f2 = _pluginInjectionApi$f.actions) === null || _pluginInjectionApi$f2 === void 0 ? void 0 : _pluginInjectionApi$f2.forceFocusSelector; const { mediaInline } = state.schema.nodes; const mediaType = state.selection instanceof NodeSelection && state.selection.node.attrs.type; const mediaLinkingState = getMediaLinkingState(state); if (mediaPluginState.allowInlineImages && isImage(mediaType)) { return getMediaInlineImageToolbar(state, intl, mediaPluginState, hoverDecoration, editorAnalyticsAPI, pluginInjectionApi, mediaLinkingState, options); } const items = []; const areAnyNewToolbarFlagsEnabled = areToolbarFlagsEnabled(Boolean(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.toolbar)); const preview = { id: 'editor.media.viewer', testId: 'file-preview-toolbar-button', type: 'button', icon: areAnyNewToolbarFlagsEnabled ? GrowDiagonalIcon : MaximizeIcon, title: intl.formatMessage(messages.preview), onClick: () => { var _handleShowMediaViewe; return (_handleShowMediaViewe = handleShowMediaViewer({ mediaPluginState, api: pluginInjectionApi })) !== null && _handleShowMediaViewe !== void 0 ? _handleShowMediaViewe : false; }, ...(areAnyNewToolbarFlagsEnabled && { supportsViewMode: true }) }; const disableDownloadButton = getIsDownloadDisabledByDataSecurityPolicy(mediaPluginState); const download = { id: 'editor.media.card.download', type: 'button', icon: DownloadIcon, onClick: () => { downloadMedia(mediaPluginState); return true; }, disabled: disableDownloadButton, title: intl.formatMessage(messages.download), ...(areAnyNewToolbarFlagsEnabled && { supportsViewMode: true }) }; if (!areAnyNewToolbarFlagsEnabled) { items.push({ id: 'editor.media.view.switcher.inline', type: 'button', icon: ImageInlineIcon, selected: true, disabled: false, focusEditoronEnter: true, onClick: () => true, title: intl.formatMessage(cardMessages.inlineTitle), testId: 'inline-appearance', className: 'inline-appearance' // a11y. uses to force focus on item }, { id: 'editor.media.view.switcher.thumbnail', type: 'button', icon: SmartLinkCardIcon, selected: false, disabled: false, focusEditoronEnter: true, onClick: changeInlineToMediaCard(editorAnalyticsAPI, forceFocusSelector), title: intl.formatMessage(cardMessages.blockTitle), testId: 'thumbnail-appearance', className: 'thumbnail-appearance' // a11y. uses to force focus on item }, { type: 'separator' }, preview, { type: 'separator' }, download, { type: 'separator' }, { type: 'copy-button', supportsViewMode: true, items: [{ state, formatMessage: intl.formatMessage, nodeType: mediaInline }] }, { type: 'separator' }, { id: 'editor.media.delete', type: 'button', appearance: 'danger', focusEditoronEnter: true, icon: DeleteIcon, onMouseEnter: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(mediaInline, true), onMouseLeave: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(mediaInline, false), onFocus: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(mediaInline, true), onBlur: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(mediaInline, false), title: intl.formatMessage(commonMessages.remove), onClick: removeInlineCardWithAnalytics(editorAnalyticsAPI), testId: 'media-toolbar-remove-button' }); } else { const options = [{ id: 'editor.media.view.switcher.inline', title: intl.formatMessage(cardMessages.inlineTitle), onClick: () => true, selected: true, icon: /*#__PURE__*/React.createElement(ImageInlineIcon, { label: "", spacing: "spacious" }) }, { id: 'editor.media.view.switcher.thumbnail', title: intl.formatMessage(cardMessages.blockTitle), onClick: changeInlineToMediaCard(editorAnalyticsAPI, forceFocusSelector), icon: /*#__PURE__*/React.createElement(SmartLinkCardIcon, { label: "", spacing: "spacious" }) }]; const switcherDropdown = { title: intl.formatMessage(messages.fileDisplayOptions), id: 'media-group-inline-switcher-toolbar-item', testId: 'media-group-inline-switcher-dropdown', type: 'dropdown', options, icon: () => /*#__PURE__*/React.createElement(ImageInlineIcon, { label: "", spacing: "spacious" }) }; items.push(switcherDropdown, { type: 'separator', fullHeight: true }, download, { type: 'separator', supportsViewMode: true }, preview, { type: 'separator', fullHeight: true }); } return items; }; const getMediaInlineImageToolbar = (state, intl, mediaPluginState, hoverDecoration, editorAnalyticsAPI, pluginInjectionApi, mediaLinkingState, options = {}) => { var _pluginInjectionApi$w; const { mediaInline } = state.schema.nodes; const mediaInlineImageTitle = intl.formatMessage(mediaAndEmbedToolbarMessages.changeToMediaInlineImage); const mediaSingleTitle = intl.formatMessage(mediaAndEmbedToolbarMessages.changeToMediaSingle); const widthPluginState = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$w = pluginInjectionApi.width) === null || _pluginInjectionApi$w === void 0 ? void 0 : _pluginInjectionApi$w.sharedState.currentState(); const inlineImageItems = []; const isEditorControlsEnabled = areToolbarFlagsEnabled(Boolean(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.toolbar)); const { isViewOnly, allowAltTextOnImages, allowLinking, allowImagePreview } = options; if (shouldShowImageBorder(state)) { inlineImageItems.push({ type: 'custom', fallback: [], render: editorView => { if (!editorView) { return null; } const { dispatch, state } = editorView; const borderMark = currentMediaOrInlineNodeBorderMark(state); return /*#__PURE__*/React.createElement(ImageBorderItem // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , { toggleBorder: () => { var _pluginInjectionApi$a2; toggleBorderMark(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a2 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a2 === void 0 ? void 0 : _pluginInjectionApi$a2.actions)(state, dispatch); } // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , setBorder: attrs => { var _pluginInjectionApi$a3; setBorderMark(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a3 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a3 === void 0 ? void 0 : _pluginInjectionApi$a3.actions)(attrs)(state, dispatch); }, borderMark: borderMark, intl: intl }); } }); if (!isEditorControlsEnabled) { inlineImageItems.push({ type: 'separator' }); } } const download = { id: 'editor.media.image.download', type: 'button', icon: DownloadIcon, onClick: () => { downloadMedia(mediaPluginState, options.isViewOnly); return true; }, title: intl.formatMessage(messages.download), supportsViewMode: true }; // For Editor Controls: show options to convert from 'Inline' to 'Original size' via dropdown if (!isEditorControlsEnabled) { inlineImageItems.push({ id: 'editor.media.convert.mediainline', type: 'button', title: mediaInlineImageTitle, icon: () => /*#__PURE__*/React.createElement(ImageInlineIcon, { color: "currentColor", spacing: "spacious", label: mediaInlineImageTitle }), onClick: () => { return true; }, selected: true }, { id: 'editor.media.convert.mediasingle', type: 'button', title: mediaSingleTitle, icon: () => /*#__PURE__*/React.createElement(ImageFullscreenIcon, { color: "currentColor", spacing: "spacious", label: mediaSingleTitle }), onClick: changeMediaInlineToMediaSingle(editorAnalyticsAPI, widthPluginState, options === null || options === void 0 ? void 0 : options.allowPixelResizing) }, { type: 'separator' }, { type: 'custom', fallback: [], render: (editorView, idx) => { if (editorView !== null && editorView !== void 0 && editorView.state) { const editLink = () => { if (editorView) { const { state, dispatch } = editorView; showLinkingToolbar(state, dispatch); } }; const openLink = () => { if (editorView) { var _pluginInjectionApi$a4; const { state: { tr }, dispatch } = editorView; pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a4 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a4 === void 0 ? void 0 : _pluginInjectionApi$a4.actions.attachAnalyticsEvent({ eventType: EVENT_TYPE.TRACK, action: ACTION.VISITED, actionSubject: ACTION_SUBJECT.MEDIA, actionSubjectId: ACTION_SUBJECT_ID.LINK })(tr); dispatch(tr); return true; } }; return /*#__PURE__*/React.createElement(LinkToolbarAppearance, { key: idx, editorState: editorView.state, intl: intl, mediaLinkingState: mediaLinkingState, onAddLink: editLink, onEditLink: editLink, onOpenLink: openLink, isInlineNode: true, isViewOnly: options.isViewOnly, areAnyNewToolbarFlagsEnabled: areToolbarFlagsEnabled(Boolean(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.toolbar)) }); } return null; }, supportsViewMode: true }); } else { const switchFromInlineToBlock = getMediaSingleAndMediaInlineSwitcherDropdown('inline', intl, pluginInjectionApi); inlineImageItems.push(switchFromInlineToBlock, { type: 'separator', fullHeight: true }); if (isViewOnly) { inlineImageItems.push(download, { type: 'separator', supportsViewMode: true }); } } //Image Preview if (allowImagePreview) { inlineImageItems.push({ id: 'editor.media.viewer', testId: 'file-preview-toolbar-button', type: 'button', icon: isEditorControlsEnabled ? GrowDiagonalIcon : MaximizeIcon, title: intl.formatMessage(messages.preview), onClick: () => { var _handleShowMediaViewe2; return (_handleShowMediaViewe2 = handleShowMediaViewer({ mediaPluginState, api: pluginInjectionApi })) !== null && _handleShowMediaViewe2 !== void 0 ? _handleShowMediaViewe2 : false; }, supportsViewMode: true }, { type: 'separator', supportsViewMode: true }); } // open link if (allowLinking && shouldShowMediaLinkToolbar(state) && mediaLinkingState && mediaLinkingState.editable && isEditorControlsEnabled) { inlineImageItems.push(getOpenLinkToolbarButtonOption(intl, mediaLinkingState, pluginInjectionApi), { type: 'separator', supportsViewMode: true }); } if (isViewOnly && !isEditorControlsEnabled) { inlineImageItems.push(download, { type: 'separator', supportsViewMode: true }); } if (allowAltTextOnImages && !isEditorControlsEnabled) { var _pluginInjectionApi$a5; inlineImageItems.push(altTextButton(intl, state, pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a5 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a5 === void 0 ? void 0 : _pluginInjectionApi$a5.actions), { type: 'separator' }); } if (isViewOnly || !isEditorControlsEnabled) { inlineImageItems.push({ type: 'copy-button', supportsViewMode: true, items: [{ state, formatMessage: intl.formatMessage, nodeType: mediaInline }] }); } if (!isEditorControlsEnabled) { inlineImageItems.push({ type: 'separator' }); inlineImageItems.push({ id: 'editor.media.delete', type: 'button', appearance: 'danger', focusEditoronEnter: true, icon: DeleteIcon, onMouseEnter: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(mediaInline, true), onMouseLeave: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(mediaInline, false), onFocus: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(mediaInline, true), onBlur: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(mediaInline, false), title: intl.formatMessage(commonMessages.remove), onClick: removeInlineCardWithAnalytics(editorAnalyticsAPI), testId: 'media-toolbar-remove-button' }); } return inlineImageItems; };