@atlaskit/editor-plugin-media-insert
Version:
Media Insert plugin for @atlaskit/editor-core
203 lines (199 loc) • 9.47 kB
JavaScript
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'
});
}
}));
});