UNPKG

@atlaskit/editor-plugin-media-insert

Version:

Media Insert plugin for @atlaskit/editor-core

203 lines (199 loc) 9.47 kB
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; 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) { _defineProperty(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; } import React, { useCallback } from 'react'; import { useIntl } from 'react-intl'; import Button from '@atlaskit/button/new'; import { INPUT_METHOD } from '@atlaskit/editor-common/analytics'; import { mediaInsertMessages } from '@atlaskit/editor-common/messages'; import UploadIcon from '@atlaskit/icon/core/upload'; import { Browser } from '@atlaskit/media-picker'; import { Stack } from '@atlaskit/primitives/compiled'; import SectionMessage from '@atlaskit/section-message'; import { useAnalyticsEvents } from './useAnalyticsEvents'; var INITIAL_UPLOAD_STATE = Object.freeze({ isOpen: false, error: null }); var uploadReducer = function uploadReducer(state, action) { switch (action.type) { case 'open': return _objectSpread(_objectSpread({}, INITIAL_UPLOAD_STATE), {}, { isOpen: true }); case 'close': // This is the only case where we don't reset state. This is because // onClose gets called for cancel _and_ upload, so we don't want to // reset any loading or error states that may have occured return _objectSpread(_objectSpread({}, state), {}, { isOpen: false }); case 'error': return _objectSpread(_objectSpread({}, INITIAL_UPLOAD_STATE), {}, { error: action.error }); case 'reset': return INITIAL_UPLOAD_STATE; } }; var isImagePreview = function isImagePreview(preview) { return 'dimensions' in preview; }; export var LocalMedia = /*#__PURE__*/React.forwardRef(function (_ref, ref) { var mediaProvider = _ref.mediaProvider, dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent, closeMediaInsertPicker = _ref.closeMediaInsertPicker, insertFile = _ref.insertFile; var intl = useIntl(); var strings = { upload: intl.formatMessage(mediaInsertMessages.upload), networkError: intl.formatMessage(mediaInsertMessages.localFileNetworkErrorMessage), genericError: intl.formatMessage(mediaInsertMessages.localFileErrorMessage) }; var _useAnalyticsEvents = useAnalyticsEvents(dispatchAnalyticsEvent), onUploadButtonClickedAnalytics = _useAnalyticsEvents.onUploadButtonClickedAnalytics, onUploadCommencedAnalytics = _useAnalyticsEvents.onUploadCommencedAnalytics, onUploadSuccessAnalytics = _useAnalyticsEvents.onUploadSuccessAnalytics, onUploadFailureAnalytics = _useAnalyticsEvents.onUploadFailureAnalytics; var _React$useReducer = React.useReducer(uploadReducer, INITIAL_UPLOAD_STATE), _React$useReducer2 = _slicedToArray(_React$useReducer, 2), uploadState = _React$useReducer2[0], dispatch = _React$useReducer2[1]; var erroredFileIds = React.useState(new Set())[0]; // This is a bit horrendous. Fundementally though, `insertFile` takes a // callback that can ask for us to add listeners to any and all of the // `Browser` events for each file uplaoded. We add a track those in a // ref, call the CBs so the media-plugin can do it's thing, and then // remove all listeners `onEnd`. var eventSubscribers = React.useRef({}); var onStateChanged = React.useCallback(function (fileId) { return function (cb) { var _eventSubscribers$cur, _eventSubscribers$cur2; eventSubscribers.current = _objectSpread(_objectSpread({}, eventSubscribers.current), {}, _defineProperty({}, fileId, [].concat(_toConsumableArray((_eventSubscribers$cur = (_eventSubscribers$cur2 = eventSubscribers.current) === null || _eventSubscribers$cur2 === void 0 ? void 0 : _eventSubscribers$cur2[fileId]) !== null && _eventSubscribers$cur !== void 0 ? _eventSubscribers$cur : []), [cb]))); }; }, []); var onPreviewUpdate = function onPreviewUpdate(_ref2) { var _mediaProvider$upload; var file = _ref2.file, preview = _ref2.preview; onUploadSuccessAnalytics('local'); var isErroredFile = erroredFileIds.has(file.id); var _ref3 = isImagePreview(preview) ? preview : { dimensions: undefined, scaleFactor: undefined }, dimensions = _ref3.dimensions, scaleFactor = _ref3.scaleFactor; var mediaState = { id: file.id, collection: (_mediaProvider$upload = mediaProvider.uploadParams) === null || _mediaProvider$upload === void 0 ? void 0 : _mediaProvider$upload.collection, fileMimeType: file.type, fileSize: file.size, fileName: file.name, dimensions: dimensions, scaleFactor: scaleFactor, status: isErroredFile ? 'error' : undefined }; insertFile({ mediaState: mediaState, inputMethod: INPUT_METHOD.MEDIA_PICKER, onMediaStateChanged: onStateChanged(file.id) }); closeMediaInsertPicker(); // Probably not needed but I guess it _could_ fail to close for some reason dispatch({ type: 'reset' }); }; var uploadParams = mediaProvider.uploadParams, uploadMediaClientConfig = mediaProvider.uploadMediaClientConfig; var onEnd = useCallback(function (payload) { var _eventSubscribers$cur3, _eventSubscribers$cur4; (_eventSubscribers$cur3 = eventSubscribers.current) === null || _eventSubscribers$cur3 === void 0 || (_eventSubscribers$cur3 = _eventSubscribers$cur3[payload.file.id]) === null || _eventSubscribers$cur3 === void 0 || _eventSubscribers$cur3.forEach(function (cb) { return cb({ id: payload.file.id, status: 'ready' }); }); (_eventSubscribers$cur4 = eventSubscribers.current) === null || _eventSubscribers$cur4 === void 0 || delete _eventSubscribers$cur4[payload.file.id]; }, []); var onError = useCallback(function (_ref4) { var _eventSubscribers$cur5, _eventSubscribers$cur6; var error = _ref4.error, fileId = _ref4.fileId; // Dispatch the error events onUploadFailureAnalytics(error.name, 'local'); dispatch({ type: 'error', error: error.name }); // Update the status of the errored file erroredFileIds.add(fileId); // Update and remove listeners (_eventSubscribers$cur5 = eventSubscribers.current) === null || _eventSubscribers$cur5 === void 0 || (_eventSubscribers$cur5 = _eventSubscribers$cur5[fileId]) === null || _eventSubscribers$cur5 === void 0 || _eventSubscribers$cur5.forEach(function (cb) { return cb({ id: fileId, status: 'error', error: error }); }); (_eventSubscribers$cur6 = eventSubscribers.current) === null || _eventSubscribers$cur6 === void 0 || delete _eventSubscribers$cur6[fileId]; }, [erroredFileIds, onUploadFailureAnalytics]); return /*#__PURE__*/React.createElement(Stack, { grow: "fill", space: "space.200" }, uploadState.error && /*#__PURE__*/React.createElement(SectionMessage, { appearance: "error" }, uploadState.error === 'upload_fail' ? strings.networkError : strings.genericError), /*#__PURE__*/React.createElement(Button, { id: "local-media-upload-button" // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , iconBefore: function iconBefore() { return /*#__PURE__*/React.createElement(UploadIcon, { label: "" }); }, ref: ref, shouldFitContainer: true, isDisabled: !uploadMediaClientConfig || !uploadParams // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onClick: function onClick() { onUploadButtonClickedAnalytics(); dispatch({ type: 'open' }); } }, strings.upload), uploadMediaClientConfig && uploadParams && /*#__PURE__*/React.createElement(Browser, { isOpen: uploadState.isOpen // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , config: { uploadParams: uploadParams, multiple: true }, mediaClientConfig: uploadMediaClientConfig // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onUploadsStart: function onUploadsStart() { return onUploadCommencedAnalytics('local'); }, onPreviewUpdate: onPreviewUpdate, onEnd: onEnd // NOTE: this will fire for some errors like network failures, but not // for others like empty files. Those have their own feedback toast // owned by media. , onError: onError // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onClose: function onClose() { erroredFileIds.clear(); dispatch({ type: 'close' }); } })); });