UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

171 lines (170 loc) 5.83 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; import React from 'react'; import { useSharedPluginState } from '@atlaskit/editor-common/hooks'; import { DEFAULT_IMAGE_HEIGHT, DEFAULT_IMAGE_WIDTH } from '@atlaskit/editor-common/media-single'; import { WithProviders } from '@atlaskit/editor-common/provider-factory'; import { SelectionBasedNodeView } from '@atlaskit/editor-common/selection-based-node-view'; import { getAttrsFromUrl } from '@atlaskit/media-client'; import { updateCurrentMediaNodeAttrs } from '../../commands/helpers'; import { isMediaBlobUrlFromAttrs } from '../../utils/media-common'; import MediaNode from './media'; const MediaNodeWithProviders = ({ pluginInjectionApi, innerComponent }) => { const { widthState } = useSharedPluginState(pluginInjectionApi, ['width']); return innerComponent({ width: widthState }); }; function isMediaDecorationSpec(decoration) { return decoration.spec.type !== undefined && decoration.spec.selected !== undefined; } class MediaNodeView extends SelectionBasedNodeView { constructor(...args) { super(...args); _defineProperty(this, "isSelected", false); _defineProperty(this, "onExternalImageLoaded", dimensions => { const getPos = this.getPos; const { width, height, ...rest } = this.getAttrs(); if (!width || !height) { updateCurrentMediaNodeAttrs({ ...rest, width: width || dimensions.width, height: height || dimensions.height }, { node: this.node, getPos })(this.view.state, this.view.dispatch); } }); _defineProperty(this, "renderMediaNodeWithState", (mediaProvider, contextIdentifierProvider) => { return ({ width: editorWidth }) => { const getPos = this.getPos; const { mediaOptions } = this.reactComponentProps; const attrs = this.getAttrs(); const url = attrs.type === 'external' ? attrs.url : ''; let { width, height } = attrs; if (this.isMediaBlobUrl()) { const urlAttrs = getAttrsFromUrl(url); if (urlAttrs) { const { width: urlWidth, height: urlHeight } = urlAttrs; width = width || urlWidth; height = height || urlHeight; } } width = width || DEFAULT_IMAGE_WIDTH; height = height || DEFAULT_IMAGE_HEIGHT; // mediaSingle defines the max dimensions, so we don't need to constrain twice. const maxDimensions = { width: `100%`, height: `100%` }; const originalDimensions = { width, height }; return /*#__PURE__*/React.createElement(MediaNode, { view: this.view, node: this.node, getPos: getPos, selected: this.nodeInsideSelection(), originalDimensions: originalDimensions, maxDimensions: maxDimensions, url: url, mediaProvider: mediaProvider, contextIdentifierProvider: contextIdentifierProvider, mediaOptions: mediaOptions, onExternalImageLoaded: this.onExternalImageLoaded }); }; }); _defineProperty(this, "renderMediaNodeWithProviders", ({ mediaProvider, contextIdentifierProvider }) => { const { pluginInjectionApi } = this.reactComponentProps; return /*#__PURE__*/React.createElement(MediaNodeWithProviders, { pluginInjectionApi: pluginInjectionApi, innerComponent: this.renderMediaNodeWithState(mediaProvider, contextIdentifierProvider) }); }); } createDomRef() { const domRef = document.createElement('div'); if (this.reactComponentProps.mediaOptions && this.reactComponentProps.mediaOptions.allowMediaSingleEditable) { // workaround Chrome bug in https://product-fabric.atlassian.net/browse/ED-5379 // see also: https://github.com/ProseMirror/prosemirror/issues/884 domRef.contentEditable = 'true'; } return domRef; } viewShouldUpdate(nextNode, decorations) { const hasMediaNodeSelectedDecoration = decorations.some(decoration => isMediaDecorationSpec(decoration) && decoration.spec.type === 'media' && decoration.spec.selected); if (this.isSelected !== hasMediaNodeSelectedDecoration) { this.isSelected = hasMediaNodeSelectedDecoration; return true; } if (this.node.attrs !== nextNode.attrs) { return true; } return super.viewShouldUpdate(nextNode, decorations); } stopEvent(event) { // Don't trap right click events on media node if (['mousedown', 'contextmenu'].indexOf(event.type) !== -1) { const mouseEvent = event; if (mouseEvent.button === 2) { return true; } } return false; } getAttrs() { const { attrs } = this.node; return attrs; } isMediaBlobUrl() { const attrs = this.getAttrs(); return isMediaBlobUrlFromAttrs(attrs); } render() { const { providerFactory } = this.reactComponentProps; return /*#__PURE__*/React.createElement(WithProviders, { providers: ['mediaProvider', 'contextIdentifierProvider'], providerFactory: providerFactory, renderNode: this.renderMediaNodeWithProviders }); } } export const ReactMediaNode = (portalProviderAPI, eventDispatcher, providerFactory, mediaOptions = {}, pluginInjectionApi) => (node, view, getPos) => { const hasIntlContext = true; return new MediaNodeView(node, view, getPos, portalProviderAPI, eventDispatcher, { eventDispatcher, providerFactory, mediaOptions, pluginInjectionApi }, undefined, undefined, undefined, hasIntlContext).init(); };