@atlaskit/editor-plugin-media-insert
Version:
Media Insert plugin for @atlaskit/editor-core
212 lines (207 loc) • 10.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LocalMedia = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireWildcard(require("react"));
var _reactIntl = require("react-intl");
var _new = _interopRequireDefault(require("@atlaskit/button/new"));
var _analytics = require("@atlaskit/editor-common/analytics");
var _messages = require("@atlaskit/editor-common/messages");
var _upload = _interopRequireDefault(require("@atlaskit/icon/core/upload"));
var _mediaPicker = require("@atlaskit/media-picker");
var _compiled = require("@atlaskit/primitives/compiled");
var _sectionMessage = _interopRequireDefault(require("@atlaskit/section-message"));
var _useAnalyticsEvents2 = require("./useAnalyticsEvents");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
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) { (0, _defineProperty2.default)(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; }
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;
};
var LocalMedia = exports.LocalMedia = /*#__PURE__*/_react.default.forwardRef(function (_ref, ref) {
var mediaProvider = _ref.mediaProvider,
dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent,
closeMediaInsertPicker = _ref.closeMediaInsertPicker,
insertFile = _ref.insertFile;
var intl = (0, _reactIntl.useIntl)();
var strings = {
upload: intl.formatMessage(_messages.mediaInsertMessages.upload),
networkError: intl.formatMessage(_messages.mediaInsertMessages.localFileNetworkErrorMessage),
genericError: intl.formatMessage(_messages.mediaInsertMessages.localFileErrorMessage)
};
var _useAnalyticsEvents = (0, _useAnalyticsEvents2.useAnalyticsEvents)(dispatchAnalyticsEvent),
onUploadButtonClickedAnalytics = _useAnalyticsEvents.onUploadButtonClickedAnalytics,
onUploadCommencedAnalytics = _useAnalyticsEvents.onUploadCommencedAnalytics,
onUploadSuccessAnalytics = _useAnalyticsEvents.onUploadSuccessAnalytics,
onUploadFailureAnalytics = _useAnalyticsEvents.onUploadFailureAnalytics;
var _React$useReducer = _react.default.useReducer(uploadReducer, INITIAL_UPLOAD_STATE),
_React$useReducer2 = (0, _slicedToArray2.default)(_React$useReducer, 2),
uploadState = _React$useReducer2[0],
dispatch = _React$useReducer2[1];
var erroredFileIds = _react.default.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.default.useRef({});
var onStateChanged = _react.default.useCallback(function (fileId) {
return function (cb) {
var _eventSubscribers$cur, _eventSubscribers$cur2;
eventSubscribers.current = _objectSpread(_objectSpread({}, eventSubscribers.current), {}, (0, _defineProperty2.default)({}, fileId, [].concat((0, _toConsumableArray2.default)((_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: _analytics.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 = (0, _react.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 = (0, _react.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.default.createElement(_compiled.Stack, {
grow: "fill",
space: "space.200"
}, uploadState.error && /*#__PURE__*/_react.default.createElement(_sectionMessage.default, {
appearance: "error"
}, uploadState.error === 'upload_fail' ? strings.networkError : strings.genericError), /*#__PURE__*/_react.default.createElement(_new.default, {
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.default.createElement(_upload.default, {
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.default.createElement(_mediaPicker.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'
});
}
}));
});