@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
@@ -74,18 +74,20 @@ export function MediaFromURL({
74
74
  insert: intl.formatMessage(mediaInsertMessages.insert),
75
75
  pasteLinkToUpload: intl.formatMessage(mediaInsertMessages.pasteLinkToUpload),
76
76
  cancel: intl.formatMessage(mediaInsertMessages.cancel),
77
- errorMessage: intl.formatMessage(mediaInsertMessages.errorMessage),
78
- warning: intl.formatMessage(mediaInsertMessages.warning)
77
+ errorMessage: intl.formatMessage(mediaInsertMessages.fromUrlErrorMessage),
78
+ warning: intl.formatMessage(mediaInsertMessages.fromUrlWarning)
79
79
  };
80
80
  const [inputUrl, setUrl] = React.useState('');
81
81
  const [previewState, dispatch] = React.useReducer(previewStateReducer, INITIAL_PREVIEW_STATE);
82
82
  const pasteFlag = React.useRef(false);
83
83
  const {
84
- onUploadAnalytics,
84
+ onUploadButtonClickedAnalytics,
85
+ onUploadCommencedAnalytics,
85
86
  onUploadSuccessAnalytics,
86
87
  onUploadFailureAnalytics
87
88
  } = useAnalyticsEvents(dispatchAnalyticsEvent);
88
89
  const uploadExternalMedia = React.useCallback(async url => {
90
+ onUploadButtonClickedAnalytics();
89
91
  dispatch({
90
92
  type: 'loading'
91
93
  });
@@ -98,13 +100,13 @@ export function MediaFromURL({
98
100
  }
99
101
  const mediaClient = getMediaClient(uploadMediaClientConfig);
100
102
  const collection = uploadParams === null || uploadParams === void 0 ? void 0 : uploadParams.collection;
101
- onUploadAnalytics();
103
+ onUploadCommencedAnalytics('url');
102
104
  try {
103
105
  const {
104
106
  uploadableFileUpfrontIds,
105
107
  dimensions
106
108
  } = await mediaClient.file.uploadExternal(url, collection);
107
- onUploadSuccessAnalytics();
109
+ onUploadSuccessAnalytics('url');
108
110
  dispatch({
109
111
  type: 'success',
110
112
  payload: {
@@ -120,7 +122,7 @@ export function MediaFromURL({
120
122
  // TODO: Make sure this gets good unit test coverage with the actual
121
123
  // media plugin. This hard coded error message could be changed at any
122
124
  // point and we need a unit test to break to stop people changing it.
123
- onUploadFailureAnalytics(e);
125
+ onUploadFailureAnalytics(e, 'url');
124
126
  dispatch({
125
127
  type: 'warning',
126
128
  warning: e,
@@ -128,20 +130,20 @@ export function MediaFromURL({
128
130
  });
129
131
  } else if (e instanceof Error) {
130
132
  const message = 'Image preview fetch failed';
131
- onUploadFailureAnalytics(message);
133
+ onUploadFailureAnalytics(message, 'url');
132
134
  dispatch({
133
135
  type: 'error',
134
136
  error: message
135
137
  });
136
138
  } else {
137
- onUploadFailureAnalytics('Unknown error');
139
+ onUploadFailureAnalytics('Unknown error', 'url');
138
140
  dispatch({
139
141
  type: 'error',
140
142
  error: 'Unknown error'
141
143
  });
142
144
  }
143
145
  }
144
- }, [mediaProvider, onUploadAnalytics, onUploadFailureAnalytics, onUploadSuccessAnalytics, inputUrl]);
146
+ }, [onUploadButtonClickedAnalytics, mediaProvider, onUploadCommencedAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics, inputUrl]);
145
147
  const onURLChange = React.useCallback(e => {
146
148
  const url = e.target.value;
147
149
  setUrl(url);
@@ -3,7 +3,8 @@ import { useIntl } from 'react-intl-next';
3
3
  import { mediaInsertMessages } from '@atlaskit/editor-common/messages';
4
4
  import { Box } from '@atlaskit/primitives';
5
5
  import Tabs, { Tab, TabList, TabPanel } from '@atlaskit/tabs';
6
- import { MediaFromURL } from './FromURL';
6
+ import { LocalMedia } from './LocalMedia';
7
+ import { MediaFromURL } from './MediaFromURL';
7
8
  export const MediaInsertContent = ({
8
9
  mediaProvider,
9
10
  dispatchAnalyticsEvent,
@@ -14,7 +15,12 @@ export const MediaInsertContent = ({
14
15
  id: "media-insert-tab-navigation"
15
16
  }, /*#__PURE__*/React.createElement(Box, {
16
17
  paddingBlockEnd: "space.150"
17
- }, /*#__PURE__*/React.createElement(TabList, null, /*#__PURE__*/React.createElement(Tab, null, intl.formatMessage(mediaInsertMessages.linkTabTitle)))), /*#__PURE__*/React.createElement(TabPanel, null, /*#__PURE__*/React.createElement(MediaFromURL, {
18
+ }, /*#__PURE__*/React.createElement(TabList, null, /*#__PURE__*/React.createElement(Tab, null, intl.formatMessage(mediaInsertMessages.fileTabTitle)), /*#__PURE__*/React.createElement(Tab, null, intl.formatMessage(mediaInsertMessages.linkTabTitle)))), /*#__PURE__*/React.createElement(TabPanel, null, /*#__PURE__*/React.createElement(LocalMedia, {
19
+ mediaProvider: mediaProvider,
20
+ onInsert: () => {},
21
+ onClose: closeMediaInsertPicker,
22
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent
23
+ })), /*#__PURE__*/React.createElement(TabPanel, null, /*#__PURE__*/React.createElement(MediaFromURL, {
18
24
  mediaProvider: mediaProvider,
19
25
  onExternalInsert: () => {},
20
26
  onInsert: () => {},
@@ -6,6 +6,7 @@ import { mediaInsertMessages } from '@atlaskit/editor-common/messages';
6
6
  import { Popup, withOuterListeners } from '@atlaskit/editor-common/ui';
7
7
  import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
8
8
  import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles';
9
+ import { useFocusEditor } from '../hooks/use-focus-editor';
9
10
  import { MediaInsertContent } from './MediaInsertContent';
10
11
  import { MediaInsertWrapper } from './MediaInsertWrapper';
11
12
  const PopupWithListeners = withOuterListeners(Popup);
@@ -46,6 +47,9 @@ export const MediaInsertPicker = ({
46
47
  const isOpen = (_useSharedPluginState = useSharedPluginState(api, ['mediaInsert'])) === null || _useSharedPluginState === void 0 ? void 0 : (_useSharedPluginState2 = _useSharedPluginState.mediaInsertState) === null || _useSharedPluginState2 === void 0 ? void 0 : _useSharedPluginState2.isOpen;
47
48
  const mediaProvider = (_useSharedPluginState3 = useSharedPluginState(api, ['media'])) === null || _useSharedPluginState3 === void 0 ? void 0 : (_useSharedPluginState4 = _useSharedPluginState3.mediaState) === null || _useSharedPluginState4 === void 0 ? void 0 : _useSharedPluginState4.mediaProvider;
48
49
  const intl = useIntl();
50
+ const focusEditor = useFocusEditor({
51
+ editorView
52
+ });
49
53
  if (!isOpen || !mediaProvider) {
50
54
  return null;
51
55
  }
@@ -64,6 +68,7 @@ export const MediaInsertPicker = ({
64
68
  dispatchAnalyticsEvent(payload);
65
69
  }
66
70
  closeMediaInsertPicker();
71
+ focusEditor();
67
72
  };
68
73
  return /*#__PURE__*/React.createElement(PopupWithListeners, {
69
74
  ariaLabel: intl.formatMessage(mediaInsertMessages.mediaPickerPopupAriaLabel),
@@ -82,6 +87,9 @@ export const MediaInsertPicker = ({
82
87
  }, /*#__PURE__*/React.createElement(MediaInsertWrapper, null, /*#__PURE__*/React.createElement(MediaInsertContent, {
83
88
  mediaProvider: mediaProvider,
84
89
  dispatchAnalyticsEvent: dispatchAnalyticsEvent,
85
- closeMediaInsertPicker: closeMediaInsertPicker
90
+ closeMediaInsertPicker: () => {
91
+ closeMediaInsertPicker();
92
+ focusEditor();
93
+ }
86
94
  })));
87
95
  };
@@ -1,36 +1,52 @@
1
1
  import React from 'react';
2
2
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
3
3
  export function useAnalyticsEvents(dispatchAnalyticsEvent) {
4
- const onUploadAnalytics = React.useCallback(() => {
4
+ const onUploadButtonClickedAnalytics = React.useCallback(() => {
5
5
  dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 ? void 0 : dispatchAnalyticsEvent({
6
6
  action: ACTION.CLICKED,
7
7
  actionSubject: ACTION_SUBJECT.BUTTON,
8
- actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA_FROM_URL,
8
+ actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA,
9
9
  eventType: EVENT_TYPE.UI
10
10
  });
11
11
  }, [dispatchAnalyticsEvent]);
12
- const onUploadSuccessAnalytics = React.useCallback(() => {
12
+ const onUploadCommencedAnalytics = React.useCallback(mediaUploadSource => {
13
+ dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 ? void 0 : dispatchAnalyticsEvent({
14
+ action: ACTION.UPLOAD_COMMENCED,
15
+ actionSubject: ACTION_SUBJECT.MEDIA,
16
+ actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA,
17
+ eventType: EVENT_TYPE.OPERATIONAL,
18
+ attributes: {
19
+ mediaUploadSource
20
+ }
21
+ });
22
+ }, [dispatchAnalyticsEvent]);
23
+ const onUploadSuccessAnalytics = React.useCallback(mediaUploadSource => {
13
24
  dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 ? void 0 : dispatchAnalyticsEvent({
14
25
  action: ACTION.UPLOAD_SUCCEEDED,
15
26
  actionSubject: ACTION_SUBJECT.MEDIA,
16
- actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA_FROM_URL,
17
- eventType: EVENT_TYPE.OPERATIONAL
27
+ actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA,
28
+ eventType: EVENT_TYPE.OPERATIONAL,
29
+ attributes: {
30
+ mediaUploadSource
31
+ }
18
32
  });
19
33
  }, [dispatchAnalyticsEvent]);
20
- const onUploadFailureAnalytics = React.useCallback(reason => {
34
+ const onUploadFailureAnalytics = React.useCallback((reason, mediaUploadSource) => {
21
35
  dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 ? void 0 : dispatchAnalyticsEvent({
22
36
  action: ACTION.UPLOAD_FAILED,
23
37
  actionSubject: ACTION_SUBJECT.MEDIA,
24
- actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA_FROM_URL,
38
+ actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA,
25
39
  eventType: EVENT_TYPE.OPERATIONAL,
26
40
  attributes: {
27
- reason
41
+ reason,
42
+ mediaUploadSource
28
43
  }
29
44
  });
30
45
  }, [dispatchAnalyticsEvent]);
31
46
  return React.useMemo(() => ({
32
- onUploadAnalytics,
47
+ onUploadButtonClickedAnalytics,
48
+ onUploadCommencedAnalytics,
33
49
  onUploadSuccessAnalytics,
34
50
  onUploadFailureAnalytics
35
- }), [onUploadAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics]);
51
+ }), [onUploadButtonClickedAnalytics, onUploadCommencedAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics]);
36
52
  }
@@ -0,0 +1,11 @@
1
+ import { useCallback } from 'react';
2
+ export var useFocusEditor = function useFocusEditor(_ref) {
3
+ var editorView = _ref.editorView;
4
+ var focusEditor = useCallback(function () {
5
+ // use setTimeout to run this async after the call
6
+ setTimeout(function () {
7
+ return editorView.focus();
8
+ }, 0);
9
+ }, [editorView]);
10
+ return focusEditor;
11
+ };
@@ -36,8 +36,6 @@ export var mediaInsertPlugin = function mediaInsertPlugin(_ref) {
36
36
  popupsMountPoint = _ref3.popupsMountPoint,
37
37
  popupsBoundariesElement = _ref3.popupsBoundariesElement,
38
38
  popupsScrollableElement = _ref3.popupsScrollableElement;
39
- var dispatch = editorView.dispatch,
40
- state = editorView.state;
41
39
  return /*#__PURE__*/React.createElement(MediaInsertPicker, {
42
40
  api: api,
43
41
  editorView: editorView,
@@ -46,7 +44,7 @@ export var mediaInsertPlugin = function mediaInsertPlugin(_ref) {
46
44
  popupsBoundariesElement: popupsBoundariesElement,
47
45
  popupsScrollableElement: popupsScrollableElement,
48
46
  closeMediaInsertPicker: function closeMediaInsertPicker() {
49
- return dispatch(_closeMediaInsertPicker(state.tr));
47
+ editorView.dispatch(_closeMediaInsertPicker(editorView.state.tr));
50
48
  }
51
49
  });
52
50
  },
@@ -0,0 +1,127 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ 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; }
4
+ 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; }
5
+ import React from 'react';
6
+ import { useIntl } from 'react-intl-next';
7
+ import Button from '@atlaskit/button/new';
8
+ import { mediaInsertMessages } from '@atlaskit/editor-common/messages';
9
+ import UploadIcon from '@atlaskit/icon/glyph/upload';
10
+ import { Browser } from '@atlaskit/media-picker';
11
+ import { Stack } from '@atlaskit/primitives';
12
+ import SectionMessage from '@atlaskit/section-message';
13
+ import { useAnalyticsEvents } from './useAnalyticsEvents';
14
+ var INITIAL_UPLOAD_STATE = Object.freeze({
15
+ isOpen: false,
16
+ error: null
17
+ });
18
+ var uploadReducer = function uploadReducer(state, action) {
19
+ switch (action.type) {
20
+ case 'open':
21
+ return _objectSpread(_objectSpread({}, INITIAL_UPLOAD_STATE), {}, {
22
+ isOpen: true
23
+ });
24
+ case 'close':
25
+ // This is the only case where we don't reset state. This is because
26
+ // onClose gets called for cancel _and_ upload, so we don't want to
27
+ // reset any loading or error states that may have occured
28
+ return _objectSpread(_objectSpread({}, state), {}, {
29
+ isOpen: false
30
+ });
31
+ case 'error':
32
+ return _objectSpread(_objectSpread({}, INITIAL_UPLOAD_STATE), {}, {
33
+ error: action.error
34
+ });
35
+ case 'reset':
36
+ return INITIAL_UPLOAD_STATE;
37
+ }
38
+ };
39
+ var isImagePreview = function isImagePreview(preview) {
40
+ return 'dimensions' in preview;
41
+ };
42
+ export var LocalMedia = function LocalMedia(_ref) {
43
+ var mediaProvider = _ref.mediaProvider,
44
+ onInsert = _ref.onInsert,
45
+ dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent;
46
+ var intl = useIntl();
47
+ var strings = {
48
+ upload: intl.formatMessage(mediaInsertMessages.upload),
49
+ networkError: intl.formatMessage(mediaInsertMessages.localFileNetworkErrorMessage),
50
+ genericError: intl.formatMessage(mediaInsertMessages.localFileErrorMessage)
51
+ };
52
+ var _useAnalyticsEvents = useAnalyticsEvents(dispatchAnalyticsEvent),
53
+ onUploadButtonClickedAnalytics = _useAnalyticsEvents.onUploadButtonClickedAnalytics,
54
+ onUploadCommencedAnalytics = _useAnalyticsEvents.onUploadCommencedAnalytics,
55
+ onUploadSuccessAnalytics = _useAnalyticsEvents.onUploadSuccessAnalytics,
56
+ onUploadFailureAnalytics = _useAnalyticsEvents.onUploadFailureAnalytics;
57
+ var _React$useReducer = React.useReducer(uploadReducer, INITIAL_UPLOAD_STATE),
58
+ _React$useReducer2 = _slicedToArray(_React$useReducer, 2),
59
+ uploadState = _React$useReducer2[0],
60
+ dispatch = _React$useReducer2[1];
61
+ var onUpload = function onUpload(_ref2) {
62
+ var _mediaProvider$upload;
63
+ var file = _ref2.file,
64
+ preview = _ref2.preview;
65
+ onUploadSuccessAnalytics('local');
66
+ var insertPayload = {
67
+ id: file.id,
68
+ collection: (_mediaProvider$upload = mediaProvider.uploadParams) === null || _mediaProvider$upload === void 0 ? void 0 : _mediaProvider$upload.collection,
69
+ occurrenceKey: file.occurrenceKey
70
+ };
71
+ if (isImagePreview(preview)) {
72
+ insertPayload.height = preview.dimensions.height;
73
+ insertPayload.width = preview.dimensions.width;
74
+ }
75
+ onInsert(insertPayload);
76
+
77
+ // Probably not needed but I guess it _could_ fail to close for some reason
78
+ dispatch({
79
+ type: 'reset'
80
+ });
81
+ };
82
+ var uploadParams = mediaProvider.uploadParams,
83
+ uploadMediaClientConfig = mediaProvider.uploadMediaClientConfig;
84
+ return /*#__PURE__*/React.createElement(Stack, {
85
+ grow: "fill",
86
+ space: "space.200"
87
+ }, uploadState.error && /*#__PURE__*/React.createElement(SectionMessage, {
88
+ appearance: "error"
89
+ }, uploadState.error === 'upload_fail' ? strings.networkError : strings.genericError), /*#__PURE__*/React.createElement(Button, {
90
+ iconBefore: UploadIcon,
91
+ shouldFitContainer: true,
92
+ isDisabled: !uploadMediaClientConfig || !uploadParams,
93
+ onClick: function onClick() {
94
+ onUploadButtonClickedAnalytics();
95
+ dispatch({
96
+ type: 'open'
97
+ });
98
+ },
99
+ autoFocus: true
100
+ }, strings.upload), uploadMediaClientConfig && uploadParams && /*#__PURE__*/React.createElement(Browser, {
101
+ isOpen: uploadState.isOpen,
102
+ config: {
103
+ uploadParams: uploadParams
104
+ },
105
+ mediaClientConfig: uploadMediaClientConfig,
106
+ onUploadsStart: function onUploadsStart() {
107
+ onUploadCommencedAnalytics('local');
108
+ },
109
+ onPreviewUpdate: onUpload
110
+ // NOTE: this will fire for some errors like network failures, but not
111
+ // for others like empty files. Those have their own feedback toast
112
+ // owned by media.
113
+ ,
114
+ onError: function onError(payload) {
115
+ onUploadFailureAnalytics(payload.error.name, 'local');
116
+ dispatch({
117
+ type: 'error',
118
+ error: payload.error.name
119
+ });
120
+ },
121
+ onClose: function onClose() {
122
+ dispatch({
123
+ type: 'close'
124
+ });
125
+ }
126
+ }));
127
+ };
@@ -75,8 +75,8 @@ export function MediaFromURL(_ref) {
75
75
  insert: intl.formatMessage(mediaInsertMessages.insert),
76
76
  pasteLinkToUpload: intl.formatMessage(mediaInsertMessages.pasteLinkToUpload),
77
77
  cancel: intl.formatMessage(mediaInsertMessages.cancel),
78
- errorMessage: intl.formatMessage(mediaInsertMessages.errorMessage),
79
- warning: intl.formatMessage(mediaInsertMessages.warning)
78
+ errorMessage: intl.formatMessage(mediaInsertMessages.fromUrlErrorMessage),
79
+ warning: intl.formatMessage(mediaInsertMessages.fromUrlWarning)
80
80
  };
81
81
  var _React$useState = React.useState(''),
82
82
  _React$useState2 = _slicedToArray(_React$useState, 2),
@@ -88,7 +88,8 @@ export function MediaFromURL(_ref) {
88
88
  dispatch = _React$useReducer2[1];
89
89
  var pasteFlag = React.useRef(false);
90
90
  var _useAnalyticsEvents = useAnalyticsEvents(dispatchAnalyticsEvent),
91
- onUploadAnalytics = _useAnalyticsEvents.onUploadAnalytics,
91
+ onUploadButtonClickedAnalytics = _useAnalyticsEvents.onUploadButtonClickedAnalytics,
92
+ onUploadCommencedAnalytics = _useAnalyticsEvents.onUploadCommencedAnalytics,
92
93
  onUploadSuccessAnalytics = _useAnalyticsEvents.onUploadSuccessAnalytics,
93
94
  onUploadFailureAnalytics = _useAnalyticsEvents.onUploadFailureAnalytics;
94
95
  var uploadExternalMedia = React.useCallback( /*#__PURE__*/function () {
@@ -97,27 +98,28 @@ export function MediaFromURL(_ref) {
97
98
  return _regeneratorRuntime.wrap(function _callee$(_context) {
98
99
  while (1) switch (_context.prev = _context.next) {
99
100
  case 0:
101
+ onUploadButtonClickedAnalytics();
100
102
  dispatch({
101
103
  type: 'loading'
102
104
  });
103
105
  uploadMediaClientConfig = mediaProvider.uploadMediaClientConfig, uploadParams = mediaProvider.uploadParams;
104
106
  if (uploadMediaClientConfig) {
105
- _context.next = 4;
107
+ _context.next = 5;
106
108
  break;
107
109
  }
108
110
  return _context.abrupt("return");
109
- case 4:
111
+ case 5:
110
112
  mediaClient = getMediaClient(uploadMediaClientConfig);
111
113
  collection = uploadParams === null || uploadParams === void 0 ? void 0 : uploadParams.collection;
112
- onUploadAnalytics();
113
- _context.prev = 7;
114
- _context.next = 10;
114
+ onUploadCommencedAnalytics('url');
115
+ _context.prev = 8;
116
+ _context.next = 11;
115
117
  return mediaClient.file.uploadExternal(url, collection);
116
- case 10:
118
+ case 11:
117
119
  _yield$mediaClient$fi = _context.sent;
118
120
  uploadableFileUpfrontIds = _yield$mediaClient$fi.uploadableFileUpfrontIds;
119
121
  dimensions = _yield$mediaClient$fi.dimensions;
120
- onUploadSuccessAnalytics();
122
+ onUploadSuccessAnalytics('url');
121
123
  dispatch({
122
124
  type: 'success',
123
125
  payload: {
@@ -128,16 +130,16 @@ export function MediaFromURL(_ref) {
128
130
  occurrenceKey: uploadableFileUpfrontIds.occurrenceKey
129
131
  }
130
132
  });
131
- _context.next = 20;
133
+ _context.next = 21;
132
134
  break;
133
- case 17:
134
- _context.prev = 17;
135
- _context.t0 = _context["catch"](7);
135
+ case 18:
136
+ _context.prev = 18;
137
+ _context.t0 = _context["catch"](8);
136
138
  if (typeof _context.t0 === 'string' && _context.t0 === 'Could not download remote file') {
137
139
  // TODO: Make sure this gets good unit test coverage with the actual
138
140
  // media plugin. This hard coded error message could be changed at any
139
141
  // point and we need a unit test to break to stop people changing it.
140
- onUploadFailureAnalytics(_context.t0);
142
+ onUploadFailureAnalytics(_context.t0, 'url');
141
143
  dispatch({
142
144
  type: 'warning',
143
145
  warning: _context.t0,
@@ -145,28 +147,28 @@ export function MediaFromURL(_ref) {
145
147
  });
146
148
  } else if (_context.t0 instanceof Error) {
147
149
  message = 'Image preview fetch failed';
148
- onUploadFailureAnalytics(message);
150
+ onUploadFailureAnalytics(message, 'url');
149
151
  dispatch({
150
152
  type: 'error',
151
153
  error: message
152
154
  });
153
155
  } else {
154
- onUploadFailureAnalytics('Unknown error');
156
+ onUploadFailureAnalytics('Unknown error', 'url');
155
157
  dispatch({
156
158
  type: 'error',
157
159
  error: 'Unknown error'
158
160
  });
159
161
  }
160
- case 20:
162
+ case 21:
161
163
  case "end":
162
164
  return _context.stop();
163
165
  }
164
- }, _callee, null, [[7, 17]]);
166
+ }, _callee, null, [[8, 18]]);
165
167
  }));
166
168
  return function (_x) {
167
169
  return _ref2.apply(this, arguments);
168
170
  };
169
- }(), [mediaProvider, onUploadAnalytics, onUploadFailureAnalytics, onUploadSuccessAnalytics, inputUrl]);
171
+ }(), [onUploadButtonClickedAnalytics, mediaProvider, onUploadCommencedAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics, inputUrl]);
170
172
  var onURLChange = React.useCallback(function (e) {
171
173
  var url = e.target.value;
172
174
  setUrl(url);
@@ -3,7 +3,8 @@ import { useIntl } from 'react-intl-next';
3
3
  import { mediaInsertMessages } from '@atlaskit/editor-common/messages';
4
4
  import { Box } from '@atlaskit/primitives';
5
5
  import Tabs, { Tab, TabList, TabPanel } from '@atlaskit/tabs';
6
- import { MediaFromURL } from './FromURL';
6
+ import { LocalMedia } from './LocalMedia';
7
+ import { MediaFromURL } from './MediaFromURL';
7
8
  export var MediaInsertContent = function MediaInsertContent(_ref) {
8
9
  var mediaProvider = _ref.mediaProvider,
9
10
  dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent,
@@ -13,7 +14,12 @@ export var MediaInsertContent = function MediaInsertContent(_ref) {
13
14
  id: "media-insert-tab-navigation"
14
15
  }, /*#__PURE__*/React.createElement(Box, {
15
16
  paddingBlockEnd: "space.150"
16
- }, /*#__PURE__*/React.createElement(TabList, null, /*#__PURE__*/React.createElement(Tab, null, intl.formatMessage(mediaInsertMessages.linkTabTitle)))), /*#__PURE__*/React.createElement(TabPanel, null, /*#__PURE__*/React.createElement(MediaFromURL, {
17
+ }, /*#__PURE__*/React.createElement(TabList, null, /*#__PURE__*/React.createElement(Tab, null, intl.formatMessage(mediaInsertMessages.fileTabTitle)), /*#__PURE__*/React.createElement(Tab, null, intl.formatMessage(mediaInsertMessages.linkTabTitle)))), /*#__PURE__*/React.createElement(TabPanel, null, /*#__PURE__*/React.createElement(LocalMedia, {
18
+ mediaProvider: mediaProvider,
19
+ onInsert: function onInsert() {},
20
+ onClose: closeMediaInsertPicker,
21
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent
22
+ })), /*#__PURE__*/React.createElement(TabPanel, null, /*#__PURE__*/React.createElement(MediaFromURL, {
17
23
  mediaProvider: mediaProvider,
18
24
  onExternalInsert: function onExternalInsert() {},
19
25
  onInsert: function onInsert() {},
@@ -6,6 +6,7 @@ import { mediaInsertMessages } from '@atlaskit/editor-common/messages';
6
6
  import { Popup, withOuterListeners } from '@atlaskit/editor-common/ui';
7
7
  import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
8
8
  import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles';
9
+ import { useFocusEditor } from '../hooks/use-focus-editor';
9
10
  import { MediaInsertContent } from './MediaInsertContent';
10
11
  import { MediaInsertWrapper } from './MediaInsertWrapper';
11
12
  var PopupWithListeners = withOuterListeners(Popup);
@@ -40,11 +41,14 @@ export var MediaInsertPicker = function MediaInsertPicker(_ref) {
40
41
  popupsMountPoint = _ref.popupsMountPoint,
41
42
  popupsBoundariesElement = _ref.popupsBoundariesElement,
42
43
  popupsScrollableElement = _ref.popupsScrollableElement,
43
- closeMediaInsertPicker = _ref.closeMediaInsertPicker;
44
+ _closeMediaInsertPicker = _ref.closeMediaInsertPicker;
44
45
  var targetRef = getDomRefFromSelection(editorView, dispatchAnalyticsEvent);
45
46
  var isOpen = (_useSharedPluginState = useSharedPluginState(api, ['mediaInsert'])) === null || _useSharedPluginState === void 0 || (_useSharedPluginState = _useSharedPluginState.mediaInsertState) === null || _useSharedPluginState === void 0 ? void 0 : _useSharedPluginState.isOpen;
46
47
  var mediaProvider = (_useSharedPluginState2 = useSharedPluginState(api, ['media'])) === null || _useSharedPluginState2 === void 0 || (_useSharedPluginState2 = _useSharedPluginState2.mediaState) === null || _useSharedPluginState2 === void 0 ? void 0 : _useSharedPluginState2.mediaProvider;
47
48
  var intl = useIntl();
49
+ var focusEditor = useFocusEditor({
50
+ editorView: editorView
51
+ });
48
52
  if (!isOpen || !mediaProvider) {
49
53
  return null;
50
54
  }
@@ -63,7 +67,8 @@ export var MediaInsertPicker = function MediaInsertPicker(_ref) {
63
67
  };
64
68
  dispatchAnalyticsEvent(payload);
65
69
  }
66
- closeMediaInsertPicker();
70
+ _closeMediaInsertPicker();
71
+ focusEditor();
67
72
  };
68
73
  };
69
74
  return /*#__PURE__*/React.createElement(PopupWithListeners, {
@@ -83,6 +88,9 @@ export var MediaInsertPicker = function MediaInsertPicker(_ref) {
83
88
  }, /*#__PURE__*/React.createElement(MediaInsertWrapper, null, /*#__PURE__*/React.createElement(MediaInsertContent, {
84
89
  mediaProvider: mediaProvider,
85
90
  dispatchAnalyticsEvent: dispatchAnalyticsEvent,
86
- closeMediaInsertPicker: closeMediaInsertPicker
91
+ closeMediaInsertPicker: function closeMediaInsertPicker() {
92
+ _closeMediaInsertPicker();
93
+ focusEditor();
94
+ }
87
95
  })));
88
96
  };
@@ -1,38 +1,54 @@
1
1
  import React from 'react';
2
2
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
3
3
  export function useAnalyticsEvents(dispatchAnalyticsEvent) {
4
- var onUploadAnalytics = React.useCallback(function () {
4
+ var onUploadButtonClickedAnalytics = React.useCallback(function () {
5
5
  dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 || dispatchAnalyticsEvent({
6
6
  action: ACTION.CLICKED,
7
7
  actionSubject: ACTION_SUBJECT.BUTTON,
8
- actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA_FROM_URL,
8
+ actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA,
9
9
  eventType: EVENT_TYPE.UI
10
10
  });
11
11
  }, [dispatchAnalyticsEvent]);
12
- var onUploadSuccessAnalytics = React.useCallback(function () {
12
+ var onUploadCommencedAnalytics = React.useCallback(function (mediaUploadSource) {
13
+ dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 || dispatchAnalyticsEvent({
14
+ action: ACTION.UPLOAD_COMMENCED,
15
+ actionSubject: ACTION_SUBJECT.MEDIA,
16
+ actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA,
17
+ eventType: EVENT_TYPE.OPERATIONAL,
18
+ attributes: {
19
+ mediaUploadSource: mediaUploadSource
20
+ }
21
+ });
22
+ }, [dispatchAnalyticsEvent]);
23
+ var onUploadSuccessAnalytics = React.useCallback(function (mediaUploadSource) {
13
24
  dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 || dispatchAnalyticsEvent({
14
25
  action: ACTION.UPLOAD_SUCCEEDED,
15
26
  actionSubject: ACTION_SUBJECT.MEDIA,
16
- actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA_FROM_URL,
17
- eventType: EVENT_TYPE.OPERATIONAL
27
+ actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA,
28
+ eventType: EVENT_TYPE.OPERATIONAL,
29
+ attributes: {
30
+ mediaUploadSource: mediaUploadSource
31
+ }
18
32
  });
19
33
  }, [dispatchAnalyticsEvent]);
20
- var onUploadFailureAnalytics = React.useCallback(function (reason) {
34
+ var onUploadFailureAnalytics = React.useCallback(function (reason, mediaUploadSource) {
21
35
  dispatchAnalyticsEvent === null || dispatchAnalyticsEvent === void 0 || dispatchAnalyticsEvent({
22
36
  action: ACTION.UPLOAD_FAILED,
23
37
  actionSubject: ACTION_SUBJECT.MEDIA,
24
- actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA_FROM_URL,
38
+ actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA,
25
39
  eventType: EVENT_TYPE.OPERATIONAL,
26
40
  attributes: {
27
- reason: reason
41
+ reason: reason,
42
+ mediaUploadSource: mediaUploadSource
28
43
  }
29
44
  });
30
45
  }, [dispatchAnalyticsEvent]);
31
46
  return React.useMemo(function () {
32
47
  return {
33
- onUploadAnalytics: onUploadAnalytics,
48
+ onUploadButtonClickedAnalytics: onUploadButtonClickedAnalytics,
49
+ onUploadCommencedAnalytics: onUploadCommencedAnalytics,
34
50
  onUploadSuccessAnalytics: onUploadSuccessAnalytics,
35
51
  onUploadFailureAnalytics: onUploadFailureAnalytics
36
52
  };
37
- }, [onUploadAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics]);
53
+ }, [onUploadButtonClickedAnalytics, onUploadCommencedAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics]);
38
54
  }
@@ -0,0 +1,4 @@
1
+ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
2
+ export declare const useFocusEditor: ({ editorView }: {
3
+ editorView: EditorView;
4
+ }) => () => void;
@@ -0,0 +1,12 @@
1
+ /// <reference types="react" />
2
+ import { type DispatchAnalyticsEvent } from '@atlaskit/editor-common/analytics';
3
+ import type { MediaProvider } from '@atlaskit/editor-common/provider-factory';
4
+ import { type OnInsertAttrs } from './types';
5
+ type Props = {
6
+ mediaProvider: MediaProvider;
7
+ onInsert: (attrs: OnInsertAttrs) => void;
8
+ onClose: () => void;
9
+ dispatchAnalyticsEvent?: DispatchAnalyticsEvent;
10
+ };
11
+ export declare const LocalMedia: ({ mediaProvider, onInsert, dispatchAnalyticsEvent }: Props) => JSX.Element;
12
+ export {};
@@ -2,7 +2,7 @@
2
2
  import type { MediaProvider } from '@atlaskit/editor-common/provider-factory';
3
3
  import { type OnInsertAttrs } from './types';
4
4
  type Props = {
5
- attrs: OnInsertAttrs;
5
+ attrs: Required<OnInsertAttrs>;
6
6
  mediaProvider: MediaProvider;
7
7
  };
8
8
  export declare const MediaCard: ({ attrs, mediaProvider }: Props) => JSX.Element;
@@ -1,7 +1,7 @@
1
1
  export type OnInsertAttrs = {
2
2
  id: string;
3
3
  collection: string | undefined;
4
- height: number;
5
- width: number;
4
+ height?: number;
5
+ width?: number;
6
6
  occurrenceKey: string | undefined;
7
7
  };