@atlaskit/editor-plugin-media-insert 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/hooks/use-focus-editor.js +17 -0
  3. package/dist/cjs/plugin.js +1 -3
  4. package/dist/cjs/ui/LocalMedia.js +134 -0
  5. package/dist/cjs/ui/{FromURL.js → MediaFromURL.js} +22 -20
  6. package/dist/cjs/ui/MediaInsertContent.js +8 -2
  7. package/dist/cjs/ui/MediaInsertPicker.js +11 -3
  8. package/dist/cjs/ui/useAnalyticsEvents.js +26 -10
  9. package/dist/es2019/hooks/use-focus-editor.js +10 -0
  10. package/dist/es2019/plugin.js +3 -5
  11. package/dist/es2019/ui/LocalMedia.js +128 -0
  12. package/dist/es2019/ui/{FromURL.js → MediaFromURL.js} +11 -9
  13. package/dist/es2019/ui/MediaInsertContent.js +8 -2
  14. package/dist/es2019/ui/MediaInsertPicker.js +9 -1
  15. package/dist/es2019/ui/useAnalyticsEvents.js +26 -10
  16. package/dist/esm/hooks/use-focus-editor.js +11 -0
  17. package/dist/esm/plugin.js +1 -3
  18. package/dist/esm/ui/LocalMedia.js +127 -0
  19. package/dist/esm/ui/{FromURL.js → MediaFromURL.js} +22 -20
  20. package/dist/esm/ui/MediaInsertContent.js +8 -2
  21. package/dist/esm/ui/MediaInsertPicker.js +11 -3
  22. package/dist/esm/ui/useAnalyticsEvents.js +26 -10
  23. package/dist/types/hooks/use-focus-editor.d.ts +4 -0
  24. package/dist/types/ui/LocalMedia.d.ts +12 -0
  25. package/dist/types/ui/MediaCard.d.ts +1 -1
  26. package/dist/types/ui/types.d.ts +2 -2
  27. package/dist/types/ui/useAnalyticsEvents.d.ts +6 -3
  28. package/dist/types-ts4.5/hooks/use-focus-editor.d.ts +4 -0
  29. package/dist/types-ts4.5/ui/LocalMedia.d.ts +12 -0
  30. package/dist/types-ts4.5/ui/MediaCard.d.ts +1 -1
  31. package/dist/types-ts4.5/ui/types.d.ts +2 -2
  32. package/dist/types-ts4.5/ui/useAnalyticsEvents.d.ts +6 -3
  33. package/package.json +4 -3
  34. /package/dist/types/ui/{FromURL.d.ts → MediaFromURL.d.ts} +0 -0
  35. /package/dist/types-ts4.5/ui/{FromURL.d.ts → MediaFromURL.d.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @atlaskit/editor-plugin-media-insert
2
2
 
3
+ ## 2.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#134463](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/134463)
8
+ [`d20ae898369bc`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/d20ae898369bc) -
9
+ [ux] [ED-24326] Add local file upload tab to media insert popup
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+
15
+ ## 2.1.2
16
+
17
+ ### Patch Changes
18
+
19
+ - [#134104](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/134104)
20
+ [`18a1de35efaf0`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/18a1de35efaf0) -
21
+ [ux] ED-24639 Make sure the editor is properly re-focused when the media insert picker is closed
22
+ - Updated dependencies
23
+
3
24
  ## 2.1.1
4
25
 
5
26
  ### Patch Changes
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useFocusEditor = void 0;
7
+ var _react = require("react");
8
+ var useFocusEditor = exports.useFocusEditor = function useFocusEditor(_ref) {
9
+ var editorView = _ref.editorView;
10
+ var focusEditor = (0, _react.useCallback)(function () {
11
+ // use setTimeout to run this async after the call
12
+ setTimeout(function () {
13
+ return editorView.focus();
14
+ }, 0);
15
+ }, [editorView]);
16
+ return focusEditor;
17
+ };
@@ -43,8 +43,6 @@ var mediaInsertPlugin = exports.mediaInsertPlugin = function mediaInsertPlugin(_
43
43
  popupsMountPoint = _ref3.popupsMountPoint,
44
44
  popupsBoundariesElement = _ref3.popupsBoundariesElement,
45
45
  popupsScrollableElement = _ref3.popupsScrollableElement;
46
- var dispatch = editorView.dispatch,
47
- state = editorView.state;
48
46
  return /*#__PURE__*/_react.default.createElement(_MediaInsertPicker.MediaInsertPicker, {
49
47
  api: api,
50
48
  editorView: editorView,
@@ -53,7 +51,7 @@ var mediaInsertPlugin = exports.mediaInsertPlugin = function mediaInsertPlugin(_
53
51
  popupsBoundariesElement: popupsBoundariesElement,
54
52
  popupsScrollableElement: popupsScrollableElement,
55
53
  closeMediaInsertPicker: function closeMediaInsertPicker() {
56
- return dispatch((0, _actions.closeMediaInsertPicker)(state.tr));
54
+ editorView.dispatch((0, _actions.closeMediaInsertPicker)(editorView.state.tr));
57
55
  }
58
56
  });
59
57
  },
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.LocalMedia = void 0;
8
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ var _react = _interopRequireDefault(require("react"));
11
+ var _reactIntlNext = require("react-intl-next");
12
+ var _new = _interopRequireDefault(require("@atlaskit/button/new"));
13
+ var _messages = require("@atlaskit/editor-common/messages");
14
+ var _upload = _interopRequireDefault(require("@atlaskit/icon/glyph/upload"));
15
+ var _mediaPicker = require("@atlaskit/media-picker");
16
+ var _primitives = require("@atlaskit/primitives");
17
+ var _sectionMessage = _interopRequireDefault(require("@atlaskit/section-message"));
18
+ var _useAnalyticsEvents2 = require("./useAnalyticsEvents");
19
+ 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; }
20
+ 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; }
21
+ var INITIAL_UPLOAD_STATE = Object.freeze({
22
+ isOpen: false,
23
+ error: null
24
+ });
25
+ var uploadReducer = function uploadReducer(state, action) {
26
+ switch (action.type) {
27
+ case 'open':
28
+ return _objectSpread(_objectSpread({}, INITIAL_UPLOAD_STATE), {}, {
29
+ isOpen: true
30
+ });
31
+ case 'close':
32
+ // This is the only case where we don't reset state. This is because
33
+ // onClose gets called for cancel _and_ upload, so we don't want to
34
+ // reset any loading or error states that may have occured
35
+ return _objectSpread(_objectSpread({}, state), {}, {
36
+ isOpen: false
37
+ });
38
+ case 'error':
39
+ return _objectSpread(_objectSpread({}, INITIAL_UPLOAD_STATE), {}, {
40
+ error: action.error
41
+ });
42
+ case 'reset':
43
+ return INITIAL_UPLOAD_STATE;
44
+ }
45
+ };
46
+ var isImagePreview = function isImagePreview(preview) {
47
+ return 'dimensions' in preview;
48
+ };
49
+ var LocalMedia = exports.LocalMedia = function LocalMedia(_ref) {
50
+ var mediaProvider = _ref.mediaProvider,
51
+ onInsert = _ref.onInsert,
52
+ dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent;
53
+ var intl = (0, _reactIntlNext.useIntl)();
54
+ var strings = {
55
+ upload: intl.formatMessage(_messages.mediaInsertMessages.upload),
56
+ networkError: intl.formatMessage(_messages.mediaInsertMessages.localFileNetworkErrorMessage),
57
+ genericError: intl.formatMessage(_messages.mediaInsertMessages.localFileErrorMessage)
58
+ };
59
+ var _useAnalyticsEvents = (0, _useAnalyticsEvents2.useAnalyticsEvents)(dispatchAnalyticsEvent),
60
+ onUploadButtonClickedAnalytics = _useAnalyticsEvents.onUploadButtonClickedAnalytics,
61
+ onUploadCommencedAnalytics = _useAnalyticsEvents.onUploadCommencedAnalytics,
62
+ onUploadSuccessAnalytics = _useAnalyticsEvents.onUploadSuccessAnalytics,
63
+ onUploadFailureAnalytics = _useAnalyticsEvents.onUploadFailureAnalytics;
64
+ var _React$useReducer = _react.default.useReducer(uploadReducer, INITIAL_UPLOAD_STATE),
65
+ _React$useReducer2 = (0, _slicedToArray2.default)(_React$useReducer, 2),
66
+ uploadState = _React$useReducer2[0],
67
+ dispatch = _React$useReducer2[1];
68
+ var onUpload = function onUpload(_ref2) {
69
+ var _mediaProvider$upload;
70
+ var file = _ref2.file,
71
+ preview = _ref2.preview;
72
+ onUploadSuccessAnalytics('local');
73
+ var insertPayload = {
74
+ id: file.id,
75
+ collection: (_mediaProvider$upload = mediaProvider.uploadParams) === null || _mediaProvider$upload === void 0 ? void 0 : _mediaProvider$upload.collection,
76
+ occurrenceKey: file.occurrenceKey
77
+ };
78
+ if (isImagePreview(preview)) {
79
+ insertPayload.height = preview.dimensions.height;
80
+ insertPayload.width = preview.dimensions.width;
81
+ }
82
+ onInsert(insertPayload);
83
+
84
+ // Probably not needed but I guess it _could_ fail to close for some reason
85
+ dispatch({
86
+ type: 'reset'
87
+ });
88
+ };
89
+ var uploadParams = mediaProvider.uploadParams,
90
+ uploadMediaClientConfig = mediaProvider.uploadMediaClientConfig;
91
+ return /*#__PURE__*/_react.default.createElement(_primitives.Stack, {
92
+ grow: "fill",
93
+ space: "space.200"
94
+ }, uploadState.error && /*#__PURE__*/_react.default.createElement(_sectionMessage.default, {
95
+ appearance: "error"
96
+ }, uploadState.error === 'upload_fail' ? strings.networkError : strings.genericError), /*#__PURE__*/_react.default.createElement(_new.default, {
97
+ iconBefore: _upload.default,
98
+ shouldFitContainer: true,
99
+ isDisabled: !uploadMediaClientConfig || !uploadParams,
100
+ onClick: function onClick() {
101
+ onUploadButtonClickedAnalytics();
102
+ dispatch({
103
+ type: 'open'
104
+ });
105
+ },
106
+ autoFocus: true
107
+ }, strings.upload), uploadMediaClientConfig && uploadParams && /*#__PURE__*/_react.default.createElement(_mediaPicker.Browser, {
108
+ isOpen: uploadState.isOpen,
109
+ config: {
110
+ uploadParams: uploadParams
111
+ },
112
+ mediaClientConfig: uploadMediaClientConfig,
113
+ onUploadsStart: function onUploadsStart() {
114
+ onUploadCommencedAnalytics('local');
115
+ },
116
+ onPreviewUpdate: onUpload
117
+ // NOTE: this will fire for some errors like network failures, but not
118
+ // for others like empty files. Those have their own feedback toast
119
+ // owned by media.
120
+ ,
121
+ onError: function onError(payload) {
122
+ onUploadFailureAnalytics(payload.error.name, 'local');
123
+ dispatch({
124
+ type: 'error',
125
+ error: payload.error.name
126
+ });
127
+ },
128
+ onClose: function onClose() {
129
+ dispatch({
130
+ type: 'close'
131
+ });
132
+ }
133
+ }));
134
+ };
@@ -82,8 +82,8 @@ function MediaFromURL(_ref) {
82
82
  insert: intl.formatMessage(_messages.mediaInsertMessages.insert),
83
83
  pasteLinkToUpload: intl.formatMessage(_messages.mediaInsertMessages.pasteLinkToUpload),
84
84
  cancel: intl.formatMessage(_messages.mediaInsertMessages.cancel),
85
- errorMessage: intl.formatMessage(_messages.mediaInsertMessages.errorMessage),
86
- warning: intl.formatMessage(_messages.mediaInsertMessages.warning)
85
+ errorMessage: intl.formatMessage(_messages.mediaInsertMessages.fromUrlErrorMessage),
86
+ warning: intl.formatMessage(_messages.mediaInsertMessages.fromUrlWarning)
87
87
  };
88
88
  var _React$useState = _react.default.useState(''),
89
89
  _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
@@ -95,7 +95,8 @@ function MediaFromURL(_ref) {
95
95
  dispatch = _React$useReducer2[1];
96
96
  var pasteFlag = _react.default.useRef(false);
97
97
  var _useAnalyticsEvents = (0, _useAnalyticsEvents2.useAnalyticsEvents)(dispatchAnalyticsEvent),
98
- onUploadAnalytics = _useAnalyticsEvents.onUploadAnalytics,
98
+ onUploadButtonClickedAnalytics = _useAnalyticsEvents.onUploadButtonClickedAnalytics,
99
+ onUploadCommencedAnalytics = _useAnalyticsEvents.onUploadCommencedAnalytics,
99
100
  onUploadSuccessAnalytics = _useAnalyticsEvents.onUploadSuccessAnalytics,
100
101
  onUploadFailureAnalytics = _useAnalyticsEvents.onUploadFailureAnalytics;
101
102
  var uploadExternalMedia = _react.default.useCallback( /*#__PURE__*/function () {
@@ -104,27 +105,28 @@ function MediaFromURL(_ref) {
104
105
  return _regenerator.default.wrap(function _callee$(_context) {
105
106
  while (1) switch (_context.prev = _context.next) {
106
107
  case 0:
108
+ onUploadButtonClickedAnalytics();
107
109
  dispatch({
108
110
  type: 'loading'
109
111
  });
110
112
  uploadMediaClientConfig = mediaProvider.uploadMediaClientConfig, uploadParams = mediaProvider.uploadParams;
111
113
  if (uploadMediaClientConfig) {
112
- _context.next = 4;
114
+ _context.next = 5;
113
115
  break;
114
116
  }
115
117
  return _context.abrupt("return");
116
- case 4:
118
+ case 5:
117
119
  mediaClient = (0, _mediaClientReact.getMediaClient)(uploadMediaClientConfig);
118
120
  collection = uploadParams === null || uploadParams === void 0 ? void 0 : uploadParams.collection;
119
- onUploadAnalytics();
120
- _context.prev = 7;
121
- _context.next = 10;
121
+ onUploadCommencedAnalytics('url');
122
+ _context.prev = 8;
123
+ _context.next = 11;
122
124
  return mediaClient.file.uploadExternal(url, collection);
123
- case 10:
125
+ case 11:
124
126
  _yield$mediaClient$fi = _context.sent;
125
127
  uploadableFileUpfrontIds = _yield$mediaClient$fi.uploadableFileUpfrontIds;
126
128
  dimensions = _yield$mediaClient$fi.dimensions;
127
- onUploadSuccessAnalytics();
129
+ onUploadSuccessAnalytics('url');
128
130
  dispatch({
129
131
  type: 'success',
130
132
  payload: {
@@ -135,16 +137,16 @@ function MediaFromURL(_ref) {
135
137
  occurrenceKey: uploadableFileUpfrontIds.occurrenceKey
136
138
  }
137
139
  });
138
- _context.next = 20;
140
+ _context.next = 21;
139
141
  break;
140
- case 17:
141
- _context.prev = 17;
142
- _context.t0 = _context["catch"](7);
142
+ case 18:
143
+ _context.prev = 18;
144
+ _context.t0 = _context["catch"](8);
143
145
  if (typeof _context.t0 === 'string' && _context.t0 === 'Could not download remote file') {
144
146
  // TODO: Make sure this gets good unit test coverage with the actual
145
147
  // media plugin. This hard coded error message could be changed at any
146
148
  // point and we need a unit test to break to stop people changing it.
147
- onUploadFailureAnalytics(_context.t0);
149
+ onUploadFailureAnalytics(_context.t0, 'url');
148
150
  dispatch({
149
151
  type: 'warning',
150
152
  warning: _context.t0,
@@ -152,28 +154,28 @@ function MediaFromURL(_ref) {
152
154
  });
153
155
  } else if (_context.t0 instanceof Error) {
154
156
  message = 'Image preview fetch failed';
155
- onUploadFailureAnalytics(message);
157
+ onUploadFailureAnalytics(message, 'url');
156
158
  dispatch({
157
159
  type: 'error',
158
160
  error: message
159
161
  });
160
162
  } else {
161
- onUploadFailureAnalytics('Unknown error');
163
+ onUploadFailureAnalytics('Unknown error', 'url');
162
164
  dispatch({
163
165
  type: 'error',
164
166
  error: 'Unknown error'
165
167
  });
166
168
  }
167
- case 20:
169
+ case 21:
168
170
  case "end":
169
171
  return _context.stop();
170
172
  }
171
- }, _callee, null, [[7, 17]]);
173
+ }, _callee, null, [[8, 18]]);
172
174
  }));
173
175
  return function (_x) {
174
176
  return _ref2.apply(this, arguments);
175
177
  };
176
- }(), [mediaProvider, onUploadAnalytics, onUploadFailureAnalytics, onUploadSuccessAnalytics, inputUrl]);
178
+ }(), [onUploadButtonClickedAnalytics, mediaProvider, onUploadCommencedAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics, inputUrl]);
177
179
  var onURLChange = _react.default.useCallback(function (e) {
178
180
  var url = e.target.value;
179
181
  setUrl(url);
@@ -11,7 +11,8 @@ var _reactIntlNext = require("react-intl-next");
11
11
  var _messages = require("@atlaskit/editor-common/messages");
12
12
  var _primitives = require("@atlaskit/primitives");
13
13
  var _tabs = _interopRequireWildcard(require("@atlaskit/tabs"));
14
- var _FromURL = require("./FromURL");
14
+ var _LocalMedia = require("./LocalMedia");
15
+ var _MediaFromURL = require("./MediaFromURL");
15
16
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
16
17
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
17
18
  var MediaInsertContent = exports.MediaInsertContent = function MediaInsertContent(_ref) {
@@ -23,7 +24,12 @@ var MediaInsertContent = exports.MediaInsertContent = function MediaInsertConten
23
24
  id: "media-insert-tab-navigation"
24
25
  }, /*#__PURE__*/_react.default.createElement(_primitives.Box, {
25
26
  paddingBlockEnd: "space.150"
26
- }, /*#__PURE__*/_react.default.createElement(_tabs.TabList, null, /*#__PURE__*/_react.default.createElement(_tabs.Tab, null, intl.formatMessage(_messages.mediaInsertMessages.linkTabTitle)))), /*#__PURE__*/_react.default.createElement(_tabs.TabPanel, null, /*#__PURE__*/_react.default.createElement(_FromURL.MediaFromURL, {
27
+ }, /*#__PURE__*/_react.default.createElement(_tabs.TabList, null, /*#__PURE__*/_react.default.createElement(_tabs.Tab, null, intl.formatMessage(_messages.mediaInsertMessages.fileTabTitle)), /*#__PURE__*/_react.default.createElement(_tabs.Tab, null, intl.formatMessage(_messages.mediaInsertMessages.linkTabTitle)))), /*#__PURE__*/_react.default.createElement(_tabs.TabPanel, null, /*#__PURE__*/_react.default.createElement(_LocalMedia.LocalMedia, {
28
+ mediaProvider: mediaProvider,
29
+ onInsert: function onInsert() {},
30
+ onClose: closeMediaInsertPicker,
31
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent
32
+ })), /*#__PURE__*/_react.default.createElement(_tabs.TabPanel, null, /*#__PURE__*/_react.default.createElement(_MediaFromURL.MediaFromURL, {
27
33
  mediaProvider: mediaProvider,
28
34
  onExternalInsert: function onExternalInsert() {},
29
35
  onInsert: function onInsert() {},
@@ -13,6 +13,7 @@ var _messages = require("@atlaskit/editor-common/messages");
13
13
  var _ui = require("@atlaskit/editor-common/ui");
14
14
  var _utils = require("@atlaskit/editor-prosemirror/utils");
15
15
  var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
16
+ var _useFocusEditor = require("../hooks/use-focus-editor");
16
17
  var _MediaInsertContent = require("./MediaInsertContent");
17
18
  var _MediaInsertWrapper = require("./MediaInsertWrapper");
18
19
  var PopupWithListeners = (0, _ui.withOuterListeners)(_ui.Popup);
@@ -47,11 +48,14 @@ var MediaInsertPicker = exports.MediaInsertPicker = function MediaInsertPicker(_
47
48
  popupsMountPoint = _ref.popupsMountPoint,
48
49
  popupsBoundariesElement = _ref.popupsBoundariesElement,
49
50
  popupsScrollableElement = _ref.popupsScrollableElement,
50
- closeMediaInsertPicker = _ref.closeMediaInsertPicker;
51
+ _closeMediaInsertPicker = _ref.closeMediaInsertPicker;
51
52
  var targetRef = getDomRefFromSelection(editorView, dispatchAnalyticsEvent);
52
53
  var isOpen = (_useSharedPluginState = (0, _hooks.useSharedPluginState)(api, ['mediaInsert'])) === null || _useSharedPluginState === void 0 || (_useSharedPluginState = _useSharedPluginState.mediaInsertState) === null || _useSharedPluginState === void 0 ? void 0 : _useSharedPluginState.isOpen;
53
54
  var mediaProvider = (_useSharedPluginState2 = (0, _hooks.useSharedPluginState)(api, ['media'])) === null || _useSharedPluginState2 === void 0 || (_useSharedPluginState2 = _useSharedPluginState2.mediaState) === null || _useSharedPluginState2 === void 0 ? void 0 : _useSharedPluginState2.mediaProvider;
54
55
  var intl = (0, _reactIntlNext.useIntl)();
56
+ var focusEditor = (0, _useFocusEditor.useFocusEditor)({
57
+ editorView: editorView
58
+ });
55
59
  if (!isOpen || !mediaProvider) {
56
60
  return null;
57
61
  }
@@ -70,7 +74,8 @@ var MediaInsertPicker = exports.MediaInsertPicker = function MediaInsertPicker(_
70
74
  };
71
75
  dispatchAnalyticsEvent(payload);
72
76
  }
73
- closeMediaInsertPicker();
77
+ _closeMediaInsertPicker();
78
+ focusEditor();
74
79
  };
75
80
  };
76
81
  return /*#__PURE__*/_react.default.createElement(PopupWithListeners, {
@@ -90,6 +95,9 @@ var MediaInsertPicker = exports.MediaInsertPicker = function MediaInsertPicker(_
90
95
  }, /*#__PURE__*/_react.default.createElement(_MediaInsertWrapper.MediaInsertWrapper, null, /*#__PURE__*/_react.default.createElement(_MediaInsertContent.MediaInsertContent, {
91
96
  mediaProvider: mediaProvider,
92
97
  dispatchAnalyticsEvent: dispatchAnalyticsEvent,
93
- closeMediaInsertPicker: closeMediaInsertPicker
98
+ closeMediaInsertPicker: function closeMediaInsertPicker() {
99
+ _closeMediaInsertPicker();
100
+ focusEditor();
101
+ }
94
102
  })));
95
103
  };
@@ -8,38 +8,54 @@ exports.useAnalyticsEvents = useAnalyticsEvents;
8
8
  var _react = _interopRequireDefault(require("react"));
9
9
  var _analytics = require("@atlaskit/editor-common/analytics");
10
10
  function useAnalyticsEvents(dispatchAnalyticsEvent) {
11
- var onUploadAnalytics = _react.default.useCallback(function () {
11
+ var onUploadButtonClickedAnalytics = _react.default.useCallback(function () {
12
12
  dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 || dispatchAnalyticsEvent({
13
13
  action: _analytics.ACTION.CLICKED,
14
14
  actionSubject: _analytics.ACTION_SUBJECT.BUTTON,
15
- actionSubjectId: _analytics.ACTION_SUBJECT_ID.UPLOAD_MEDIA_FROM_URL,
15
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.UPLOAD_MEDIA,
16
16
  eventType: _analytics.EVENT_TYPE.UI
17
17
  });
18
18
  }, [dispatchAnalyticsEvent]);
19
- var onUploadSuccessAnalytics = _react.default.useCallback(function () {
19
+ var onUploadCommencedAnalytics = _react.default.useCallback(function (mediaUploadSource) {
20
+ dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 || dispatchAnalyticsEvent({
21
+ action: _analytics.ACTION.UPLOAD_COMMENCED,
22
+ actionSubject: _analytics.ACTION_SUBJECT.MEDIA,
23
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.UPLOAD_MEDIA,
24
+ eventType: _analytics.EVENT_TYPE.OPERATIONAL,
25
+ attributes: {
26
+ mediaUploadSource: mediaUploadSource
27
+ }
28
+ });
29
+ }, [dispatchAnalyticsEvent]);
30
+ var onUploadSuccessAnalytics = _react.default.useCallback(function (mediaUploadSource) {
20
31
  dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 || dispatchAnalyticsEvent({
21
32
  action: _analytics.ACTION.UPLOAD_SUCCEEDED,
22
33
  actionSubject: _analytics.ACTION_SUBJECT.MEDIA,
23
- actionSubjectId: _analytics.ACTION_SUBJECT_ID.UPLOAD_MEDIA_FROM_URL,
24
- eventType: _analytics.EVENT_TYPE.OPERATIONAL
34
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.UPLOAD_MEDIA,
35
+ eventType: _analytics.EVENT_TYPE.OPERATIONAL,
36
+ attributes: {
37
+ mediaUploadSource: mediaUploadSource
38
+ }
25
39
  });
26
40
  }, [dispatchAnalyticsEvent]);
27
- var onUploadFailureAnalytics = _react.default.useCallback(function (reason) {
41
+ var onUploadFailureAnalytics = _react.default.useCallback(function (reason, mediaUploadSource) {
28
42
  dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 || dispatchAnalyticsEvent({
29
43
  action: _analytics.ACTION.UPLOAD_FAILED,
30
44
  actionSubject: _analytics.ACTION_SUBJECT.MEDIA,
31
- actionSubjectId: _analytics.ACTION_SUBJECT_ID.UPLOAD_MEDIA_FROM_URL,
45
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.UPLOAD_MEDIA,
32
46
  eventType: _analytics.EVENT_TYPE.OPERATIONAL,
33
47
  attributes: {
34
- reason: reason
48
+ reason: reason,
49
+ mediaUploadSource: mediaUploadSource
35
50
  }
36
51
  });
37
52
  }, [dispatchAnalyticsEvent]);
38
53
  return _react.default.useMemo(function () {
39
54
  return {
40
- onUploadAnalytics: onUploadAnalytics,
55
+ onUploadButtonClickedAnalytics: onUploadButtonClickedAnalytics,
56
+ onUploadCommencedAnalytics: onUploadCommencedAnalytics,
41
57
  onUploadSuccessAnalytics: onUploadSuccessAnalytics,
42
58
  onUploadFailureAnalytics: onUploadFailureAnalytics
43
59
  };
44
- }, [onUploadAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics]);
60
+ }, [onUploadButtonClickedAnalytics, onUploadCommencedAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics]);
45
61
  }
@@ -0,0 +1,10 @@
1
+ import { useCallback } from 'react';
2
+ export const useFocusEditor = ({
3
+ editorView
4
+ }) => {
5
+ const focusEditor = useCallback(() => {
6
+ // use setTimeout to run this async after the call
7
+ setTimeout(() => editorView.focus(), 0);
8
+ }, [editorView]);
9
+ return focusEditor;
10
+ };
@@ -37,10 +37,6 @@ export const mediaInsertPlugin = ({
37
37
  popupsBoundariesElement,
38
38
  popupsScrollableElement
39
39
  }) => {
40
- const {
41
- dispatch,
42
- state
43
- } = editorView;
44
40
  return /*#__PURE__*/React.createElement(MediaInsertPicker, {
45
41
  api: api,
46
42
  editorView: editorView,
@@ -48,7 +44,9 @@ export const mediaInsertPlugin = ({
48
44
  popupsMountPoint: popupsMountPoint,
49
45
  popupsBoundariesElement: popupsBoundariesElement,
50
46
  popupsScrollableElement: popupsScrollableElement,
51
- closeMediaInsertPicker: () => dispatch(closeMediaInsertPicker(state.tr))
47
+ closeMediaInsertPicker: () => {
48
+ editorView.dispatch(closeMediaInsertPicker(editorView.state.tr));
49
+ }
52
50
  });
53
51
  },
54
52
  pluginsOptions: {
@@ -0,0 +1,128 @@
1
+ import React from 'react';
2
+ import { useIntl } from 'react-intl-next';
3
+ import Button from '@atlaskit/button/new';
4
+ import { mediaInsertMessages } from '@atlaskit/editor-common/messages';
5
+ import UploadIcon from '@atlaskit/icon/glyph/upload';
6
+ import { Browser } from '@atlaskit/media-picker';
7
+ import { Stack } from '@atlaskit/primitives';
8
+ import SectionMessage from '@atlaskit/section-message';
9
+ import { useAnalyticsEvents } from './useAnalyticsEvents';
10
+ const INITIAL_UPLOAD_STATE = Object.freeze({
11
+ isOpen: false,
12
+ error: null
13
+ });
14
+ const uploadReducer = (state, action) => {
15
+ switch (action.type) {
16
+ case 'open':
17
+ return {
18
+ ...INITIAL_UPLOAD_STATE,
19
+ isOpen: true
20
+ };
21
+ case 'close':
22
+ // This is the only case where we don't reset state. This is because
23
+ // onClose gets called for cancel _and_ upload, so we don't want to
24
+ // reset any loading or error states that may have occured
25
+ return {
26
+ ...state,
27
+ isOpen: false
28
+ };
29
+ case 'error':
30
+ return {
31
+ ...INITIAL_UPLOAD_STATE,
32
+ error: action.error
33
+ };
34
+ case 'reset':
35
+ return INITIAL_UPLOAD_STATE;
36
+ }
37
+ };
38
+ const isImagePreview = preview => {
39
+ return 'dimensions' in preview;
40
+ };
41
+ export const LocalMedia = ({
42
+ mediaProvider,
43
+ onInsert,
44
+ dispatchAnalyticsEvent
45
+ }) => {
46
+ const intl = useIntl();
47
+ const strings = {
48
+ upload: intl.formatMessage(mediaInsertMessages.upload),
49
+ networkError: intl.formatMessage(mediaInsertMessages.localFileNetworkErrorMessage),
50
+ genericError: intl.formatMessage(mediaInsertMessages.localFileErrorMessage)
51
+ };
52
+ const {
53
+ onUploadButtonClickedAnalytics,
54
+ onUploadCommencedAnalytics,
55
+ onUploadSuccessAnalytics,
56
+ onUploadFailureAnalytics
57
+ } = useAnalyticsEvents(dispatchAnalyticsEvent);
58
+ const [uploadState, dispatch] = React.useReducer(uploadReducer, INITIAL_UPLOAD_STATE);
59
+ const onUpload = ({
60
+ file,
61
+ preview
62
+ }) => {
63
+ var _mediaProvider$upload;
64
+ onUploadSuccessAnalytics('local');
65
+ const insertPayload = {
66
+ id: file.id,
67
+ collection: (_mediaProvider$upload = mediaProvider.uploadParams) === null || _mediaProvider$upload === void 0 ? void 0 : _mediaProvider$upload.collection,
68
+ occurrenceKey: file.occurrenceKey
69
+ };
70
+ if (isImagePreview(preview)) {
71
+ insertPayload.height = preview.dimensions.height;
72
+ insertPayload.width = preview.dimensions.width;
73
+ }
74
+ onInsert(insertPayload);
75
+
76
+ // Probably not needed but I guess it _could_ fail to close for some reason
77
+ dispatch({
78
+ type: 'reset'
79
+ });
80
+ };
81
+ const {
82
+ uploadParams,
83
+ uploadMediaClientConfig
84
+ } = mediaProvider;
85
+ return /*#__PURE__*/React.createElement(Stack, {
86
+ grow: "fill",
87
+ space: "space.200"
88
+ }, uploadState.error && /*#__PURE__*/React.createElement(SectionMessage, {
89
+ appearance: "error"
90
+ }, uploadState.error === 'upload_fail' ? strings.networkError : strings.genericError), /*#__PURE__*/React.createElement(Button, {
91
+ iconBefore: UploadIcon,
92
+ shouldFitContainer: true,
93
+ isDisabled: !uploadMediaClientConfig || !uploadParams,
94
+ onClick: () => {
95
+ onUploadButtonClickedAnalytics();
96
+ dispatch({
97
+ type: 'open'
98
+ });
99
+ },
100
+ autoFocus: true
101
+ }, strings.upload), uploadMediaClientConfig && uploadParams && /*#__PURE__*/React.createElement(Browser, {
102
+ isOpen: uploadState.isOpen,
103
+ config: {
104
+ uploadParams: uploadParams
105
+ },
106
+ mediaClientConfig: uploadMediaClientConfig,
107
+ onUploadsStart: () => {
108
+ onUploadCommencedAnalytics('local');
109
+ },
110
+ onPreviewUpdate: onUpload
111
+ // NOTE: this will fire for some errors like network failures, but not
112
+ // for others like empty files. Those have their own feedback toast
113
+ // owned by media.
114
+ ,
115
+ onError: payload => {
116
+ onUploadFailureAnalytics(payload.error.name, 'local');
117
+ dispatch({
118
+ type: 'error',
119
+ error: payload.error.name
120
+ });
121
+ },
122
+ onClose: () => {
123
+ dispatch({
124
+ type: 'close'
125
+ });
126
+ }
127
+ }));
128
+ };