@atlaskit/editor-plugin-media-insert 2.1.2 → 2.3.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.
- package/CHANGELOG.md +24 -0
- package/dist/cjs/plugin.js +48 -4
- package/dist/cjs/ui/LocalMedia.js +143 -0
- package/dist/cjs/ui/{FromURL.js → MediaFromURL.js} +50 -27
- package/dist/cjs/ui/MediaInsertContent.js +14 -6
- package/dist/cjs/ui/MediaInsertPicker.js +6 -2
- package/dist/cjs/ui/useAnalyticsEvents.js +26 -10
- package/dist/es2019/plugin.js +49 -3
- package/dist/es2019/ui/LocalMedia.js +137 -0
- package/dist/es2019/ui/{FromURL.js → MediaFromURL.js} +39 -16
- package/dist/es2019/ui/MediaInsertContent.js +14 -6
- package/dist/es2019/ui/MediaInsertPicker.js +6 -2
- package/dist/es2019/ui/useAnalyticsEvents.js +26 -10
- package/dist/esm/plugin.js +48 -4
- package/dist/esm/ui/LocalMedia.js +136 -0
- package/dist/esm/ui/{FromURL.js → MediaFromURL.js} +50 -27
- package/dist/esm/ui/MediaInsertContent.js +14 -6
- package/dist/esm/ui/MediaInsertPicker.js +6 -2
- package/dist/esm/ui/useAnalyticsEvents.js +26 -10
- package/dist/types/types.d.ts +13 -0
- package/dist/types/ui/LocalMedia.d.ts +12 -0
- package/dist/types/ui/MediaCard.d.ts +1 -1
- package/dist/types/ui/MediaFromURL.d.ts +13 -0
- package/dist/types/ui/MediaInsertContent.d.ts +8 -3
- package/dist/types/ui/MediaInsertPicker.d.ts +1 -1
- package/dist/types/ui/types.d.ts +3 -2
- package/dist/types/ui/useAnalyticsEvents.d.ts +6 -3
- package/dist/types-ts4.5/types.d.ts +13 -0
- package/dist/types-ts4.5/ui/LocalMedia.d.ts +12 -0
- package/dist/types-ts4.5/ui/MediaCard.d.ts +1 -1
- package/dist/types-ts4.5/ui/MediaFromURL.d.ts +13 -0
- package/dist/types-ts4.5/ui/MediaInsertContent.d.ts +8 -3
- package/dist/types-ts4.5/ui/MediaInsertPicker.d.ts +1 -1
- package/dist/types-ts4.5/ui/types.d.ts +3 -2
- package/dist/types-ts4.5/ui/useAnalyticsEvents.d.ts +6 -3
- package/package.json +6 -5
- package/dist/types/ui/FromURL.d.ts +0 -13
- package/dist/types-ts4.5/ui/FromURL.d.ts +0 -13
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl-next';
|
|
3
|
+
import Button from '@atlaskit/button/new';
|
|
4
|
+
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
5
|
+
import { mediaInsertMessages } from '@atlaskit/editor-common/messages';
|
|
6
|
+
import UploadIcon from '@atlaskit/icon/glyph/upload';
|
|
7
|
+
import { Browser } from '@atlaskit/media-picker';
|
|
8
|
+
import { Stack } from '@atlaskit/primitives';
|
|
9
|
+
import SectionMessage from '@atlaskit/section-message';
|
|
10
|
+
import { useAnalyticsEvents } from './useAnalyticsEvents';
|
|
11
|
+
const INITIAL_UPLOAD_STATE = Object.freeze({
|
|
12
|
+
isOpen: false,
|
|
13
|
+
error: null
|
|
14
|
+
});
|
|
15
|
+
const uploadReducer = (state, action) => {
|
|
16
|
+
switch (action.type) {
|
|
17
|
+
case 'open':
|
|
18
|
+
return {
|
|
19
|
+
...INITIAL_UPLOAD_STATE,
|
|
20
|
+
isOpen: true
|
|
21
|
+
};
|
|
22
|
+
case 'close':
|
|
23
|
+
// This is the only case where we don't reset state. This is because
|
|
24
|
+
// onClose gets called for cancel _and_ upload, so we don't want to
|
|
25
|
+
// reset any loading or error states that may have occured
|
|
26
|
+
return {
|
|
27
|
+
...state,
|
|
28
|
+
isOpen: false
|
|
29
|
+
};
|
|
30
|
+
case 'error':
|
|
31
|
+
return {
|
|
32
|
+
...INITIAL_UPLOAD_STATE,
|
|
33
|
+
error: action.error
|
|
34
|
+
};
|
|
35
|
+
case 'reset':
|
|
36
|
+
return INITIAL_UPLOAD_STATE;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const isImagePreview = preview => {
|
|
40
|
+
return 'dimensions' in preview;
|
|
41
|
+
};
|
|
42
|
+
export const LocalMedia = ({
|
|
43
|
+
mediaProvider,
|
|
44
|
+
onInsert,
|
|
45
|
+
dispatchAnalyticsEvent
|
|
46
|
+
}) => {
|
|
47
|
+
const intl = useIntl();
|
|
48
|
+
const strings = {
|
|
49
|
+
upload: intl.formatMessage(mediaInsertMessages.upload),
|
|
50
|
+
networkError: intl.formatMessage(mediaInsertMessages.localFileNetworkErrorMessage),
|
|
51
|
+
genericError: intl.formatMessage(mediaInsertMessages.localFileErrorMessage)
|
|
52
|
+
};
|
|
53
|
+
const {
|
|
54
|
+
onUploadButtonClickedAnalytics,
|
|
55
|
+
onUploadCommencedAnalytics,
|
|
56
|
+
onUploadSuccessAnalytics,
|
|
57
|
+
onUploadFailureAnalytics
|
|
58
|
+
} = useAnalyticsEvents(dispatchAnalyticsEvent);
|
|
59
|
+
const [uploadState, dispatch] = React.useReducer(uploadReducer, INITIAL_UPLOAD_STATE);
|
|
60
|
+
const onUpload = ({
|
|
61
|
+
file,
|
|
62
|
+
preview
|
|
63
|
+
}) => {
|
|
64
|
+
var _mediaProvider$upload;
|
|
65
|
+
onUploadSuccessAnalytics('local');
|
|
66
|
+
const mediaState = {
|
|
67
|
+
id: file.id,
|
|
68
|
+
collection: (_mediaProvider$upload = mediaProvider.uploadParams) === null || _mediaProvider$upload === void 0 ? void 0 : _mediaProvider$upload.collection,
|
|
69
|
+
fileMimeType: file.type,
|
|
70
|
+
fileSize: file.size,
|
|
71
|
+
fileName: file.name,
|
|
72
|
+
dimensions: undefined
|
|
73
|
+
};
|
|
74
|
+
if (isImagePreview(preview)) {
|
|
75
|
+
mediaState.dimensions = {
|
|
76
|
+
width: preview.dimensions.width,
|
|
77
|
+
height: preview.dimensions.height
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
onInsert({
|
|
81
|
+
mediaState,
|
|
82
|
+
inputMethod: INPUT_METHOD.MEDIA_PICKER
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Probably not needed but I guess it _could_ fail to close for some reason
|
|
86
|
+
dispatch({
|
|
87
|
+
type: 'reset'
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
const {
|
|
91
|
+
uploadParams,
|
|
92
|
+
uploadMediaClientConfig
|
|
93
|
+
} = mediaProvider;
|
|
94
|
+
return /*#__PURE__*/React.createElement(Stack, {
|
|
95
|
+
grow: "fill",
|
|
96
|
+
space: "space.200"
|
|
97
|
+
}, uploadState.error && /*#__PURE__*/React.createElement(SectionMessage, {
|
|
98
|
+
appearance: "error"
|
|
99
|
+
}, uploadState.error === 'upload_fail' ? strings.networkError : strings.genericError), /*#__PURE__*/React.createElement(Button, {
|
|
100
|
+
iconBefore: UploadIcon,
|
|
101
|
+
shouldFitContainer: true,
|
|
102
|
+
isDisabled: !uploadMediaClientConfig || !uploadParams,
|
|
103
|
+
onClick: () => {
|
|
104
|
+
onUploadButtonClickedAnalytics();
|
|
105
|
+
dispatch({
|
|
106
|
+
type: 'open'
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
autoFocus: true
|
|
110
|
+
}, strings.upload), uploadMediaClientConfig && uploadParams && /*#__PURE__*/React.createElement(Browser, {
|
|
111
|
+
isOpen: uploadState.isOpen,
|
|
112
|
+
config: {
|
|
113
|
+
uploadParams: uploadParams
|
|
114
|
+
},
|
|
115
|
+
mediaClientConfig: uploadMediaClientConfig,
|
|
116
|
+
onUploadsStart: () => {
|
|
117
|
+
onUploadCommencedAnalytics('local');
|
|
118
|
+
},
|
|
119
|
+
onPreviewUpdate: onUpload
|
|
120
|
+
// NOTE: this will fire for some errors like network failures, but not
|
|
121
|
+
// for others like empty files. Those have their own feedback toast
|
|
122
|
+
// owned by media.
|
|
123
|
+
,
|
|
124
|
+
onError: payload => {
|
|
125
|
+
onUploadFailureAnalytics(payload.error.name, 'local');
|
|
126
|
+
dispatch({
|
|
127
|
+
type: 'error',
|
|
128
|
+
error: payload.error.name
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
onClose: () => {
|
|
132
|
+
dispatch({
|
|
133
|
+
type: 'close'
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}));
|
|
137
|
+
};
|
|
@@ -63,10 +63,10 @@ const previewStateReducer = (state, action) => {
|
|
|
63
63
|
};
|
|
64
64
|
export function MediaFromURL({
|
|
65
65
|
mediaProvider,
|
|
66
|
-
onInsert,
|
|
67
|
-
onExternalInsert,
|
|
68
66
|
dispatchAnalyticsEvent,
|
|
69
|
-
closeMediaInsertPicker
|
|
67
|
+
closeMediaInsertPicker,
|
|
68
|
+
insertMediaSingle,
|
|
69
|
+
insertExternalMediaSingle
|
|
70
70
|
}) {
|
|
71
71
|
const intl = useIntl();
|
|
72
72
|
const strings = {
|
|
@@ -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.
|
|
78
|
-
warning: intl.formatMessage(mediaInsertMessages.
|
|
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
|
-
|
|
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,14 @@ 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
|
-
|
|
103
|
+
onUploadCommencedAnalytics('url');
|
|
102
104
|
try {
|
|
103
105
|
const {
|
|
104
106
|
uploadableFileUpfrontIds,
|
|
105
|
-
dimensions
|
|
107
|
+
dimensions,
|
|
108
|
+
mimeType
|
|
106
109
|
} = await mediaClient.file.uploadExternal(url, collection);
|
|
107
|
-
onUploadSuccessAnalytics();
|
|
110
|
+
onUploadSuccessAnalytics('url');
|
|
108
111
|
dispatch({
|
|
109
112
|
type: 'success',
|
|
110
113
|
payload: {
|
|
@@ -112,7 +115,8 @@ export function MediaFromURL({
|
|
|
112
115
|
collection,
|
|
113
116
|
height: dimensions.height,
|
|
114
117
|
width: dimensions.width,
|
|
115
|
-
occurrenceKey: uploadableFileUpfrontIds.occurrenceKey
|
|
118
|
+
occurrenceKey: uploadableFileUpfrontIds.occurrenceKey,
|
|
119
|
+
fileMimeType: mimeType
|
|
116
120
|
}
|
|
117
121
|
});
|
|
118
122
|
} catch (e) {
|
|
@@ -120,7 +124,7 @@ export function MediaFromURL({
|
|
|
120
124
|
// TODO: Make sure this gets good unit test coverage with the actual
|
|
121
125
|
// media plugin. This hard coded error message could be changed at any
|
|
122
126
|
// point and we need a unit test to break to stop people changing it.
|
|
123
|
-
onUploadFailureAnalytics(e);
|
|
127
|
+
onUploadFailureAnalytics(e, 'url');
|
|
124
128
|
dispatch({
|
|
125
129
|
type: 'warning',
|
|
126
130
|
warning: e,
|
|
@@ -128,20 +132,20 @@ export function MediaFromURL({
|
|
|
128
132
|
});
|
|
129
133
|
} else if (e instanceof Error) {
|
|
130
134
|
const message = 'Image preview fetch failed';
|
|
131
|
-
onUploadFailureAnalytics(message);
|
|
135
|
+
onUploadFailureAnalytics(message, 'url');
|
|
132
136
|
dispatch({
|
|
133
137
|
type: 'error',
|
|
134
138
|
error: message
|
|
135
139
|
});
|
|
136
140
|
} else {
|
|
137
|
-
onUploadFailureAnalytics('Unknown error');
|
|
141
|
+
onUploadFailureAnalytics('Unknown error', 'url');
|
|
138
142
|
dispatch({
|
|
139
143
|
type: 'error',
|
|
140
144
|
error: 'Unknown error'
|
|
141
145
|
});
|
|
142
146
|
}
|
|
143
147
|
}
|
|
144
|
-
}, [
|
|
148
|
+
}, [onUploadButtonClickedAnalytics, mediaProvider, onUploadCommencedAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics, inputUrl]);
|
|
145
149
|
const onURLChange = React.useCallback(e => {
|
|
146
150
|
const url = e.target.value;
|
|
147
151
|
setUrl(url);
|
|
@@ -164,14 +168,33 @@ export function MediaFromURL({
|
|
|
164
168
|
pasteFlag.current = true;
|
|
165
169
|
}
|
|
166
170
|
}, [inputUrl]);
|
|
171
|
+
const onInsert = React.useCallback(() => {
|
|
172
|
+
if (previewState.previewInfo) {
|
|
173
|
+
insertMediaSingle({
|
|
174
|
+
mediaState: previewState.previewInfo,
|
|
175
|
+
inputMethod: INPUT_METHOD.MEDIA_PICKER
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
closeMediaInsertPicker();
|
|
179
|
+
}, [closeMediaInsertPicker, insertMediaSingle, previewState.previewInfo]);
|
|
180
|
+
const onExternalInsert = React.useCallback(url => {
|
|
181
|
+
if (previewState.warning) {
|
|
182
|
+
insertExternalMediaSingle({
|
|
183
|
+
url,
|
|
184
|
+
alt: url,
|
|
185
|
+
inputMethod: INPUT_METHOD.MEDIA_PICKER
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
closeMediaInsertPicker();
|
|
189
|
+
}, [closeMediaInsertPicker, insertExternalMediaSingle, previewState.warning]);
|
|
167
190
|
const onInsertClick = React.useCallback(() => {
|
|
168
191
|
if (previewState.previewInfo) {
|
|
169
|
-
return onInsert(
|
|
192
|
+
return onInsert();
|
|
170
193
|
}
|
|
171
194
|
if (previewState.warning) {
|
|
172
195
|
return onExternalInsert(inputUrl);
|
|
173
196
|
}
|
|
174
|
-
}, [
|
|
197
|
+
}, [previewState.previewInfo, previewState.warning, onInsert, onExternalInsert, inputUrl]);
|
|
175
198
|
const onInputKeyPress = React.useCallback(event => {
|
|
176
199
|
if (event && event.key === 'Esc') {
|
|
177
200
|
if (dispatchAnalyticsEvent) {
|
|
@@ -3,22 +3,30 @@ 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 {
|
|
6
|
+
import { LocalMedia } from './LocalMedia';
|
|
7
|
+
import { MediaFromURL } from './MediaFromURL';
|
|
7
8
|
export const MediaInsertContent = ({
|
|
8
9
|
mediaProvider,
|
|
9
10
|
dispatchAnalyticsEvent,
|
|
10
|
-
closeMediaInsertPicker
|
|
11
|
+
closeMediaInsertPicker,
|
|
12
|
+
insertMediaSingle,
|
|
13
|
+
insertExternalMediaSingle
|
|
11
14
|
}) => {
|
|
12
15
|
const intl = useIntl();
|
|
13
16
|
return /*#__PURE__*/React.createElement(Tabs, {
|
|
14
17
|
id: "media-insert-tab-navigation"
|
|
15
18
|
}, /*#__PURE__*/React.createElement(Box, {
|
|
16
19
|
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(
|
|
20
|
+
}, /*#__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, {
|
|
21
|
+
mediaProvider: mediaProvider,
|
|
22
|
+
onInsert: insertMediaSingle,
|
|
23
|
+
onClose: closeMediaInsertPicker,
|
|
24
|
+
dispatchAnalyticsEvent: dispatchAnalyticsEvent
|
|
25
|
+
})), /*#__PURE__*/React.createElement(TabPanel, null, /*#__PURE__*/React.createElement(MediaFromURL, {
|
|
18
26
|
mediaProvider: mediaProvider,
|
|
19
|
-
onExternalInsert: () => {},
|
|
20
|
-
onInsert: () => {},
|
|
21
27
|
dispatchAnalyticsEvent: dispatchAnalyticsEvent,
|
|
22
|
-
closeMediaInsertPicker: closeMediaInsertPicker
|
|
28
|
+
closeMediaInsertPicker: closeMediaInsertPicker,
|
|
29
|
+
insertMediaSingle: insertMediaSingle,
|
|
30
|
+
insertExternalMediaSingle: insertExternalMediaSingle
|
|
23
31
|
})));
|
|
24
32
|
};
|
|
@@ -40,7 +40,9 @@ export const MediaInsertPicker = ({
|
|
|
40
40
|
popupsMountPoint,
|
|
41
41
|
popupsBoundariesElement,
|
|
42
42
|
popupsScrollableElement,
|
|
43
|
-
closeMediaInsertPicker
|
|
43
|
+
closeMediaInsertPicker,
|
|
44
|
+
insertMediaSingle,
|
|
45
|
+
insertExternalMediaSingle
|
|
44
46
|
}) => {
|
|
45
47
|
var _useSharedPluginState, _useSharedPluginState2, _useSharedPluginState3, _useSharedPluginState4;
|
|
46
48
|
const targetRef = getDomRefFromSelection(editorView, dispatchAnalyticsEvent);
|
|
@@ -90,6 +92,8 @@ export const MediaInsertPicker = ({
|
|
|
90
92
|
closeMediaInsertPicker: () => {
|
|
91
93
|
closeMediaInsertPicker();
|
|
92
94
|
focusEditor();
|
|
93
|
-
}
|
|
95
|
+
},
|
|
96
|
+
insertMediaSingle: insertMediaSingle,
|
|
97
|
+
insertExternalMediaSingle: insertExternalMediaSingle
|
|
94
98
|
})));
|
|
95
99
|
};
|
|
@@ -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
|
|
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.
|
|
8
|
+
actionSubjectId: ACTION_SUBJECT_ID.UPLOAD_MEDIA,
|
|
9
9
|
eventType: EVENT_TYPE.UI
|
|
10
10
|
});
|
|
11
11
|
}, [dispatchAnalyticsEvent]);
|
|
12
|
-
const
|
|
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.
|
|
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.
|
|
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
|
-
|
|
47
|
+
onUploadButtonClickedAnalytics,
|
|
48
|
+
onUploadCommencedAnalytics,
|
|
33
49
|
onUploadSuccessAnalytics,
|
|
34
50
|
onUploadFailureAnalytics
|
|
35
|
-
}), [
|
|
51
|
+
}), [onUploadButtonClickedAnalytics, onUploadCommencedAnalytics, onUploadSuccessAnalytics, onUploadFailureAnalytics]);
|
|
36
52
|
}
|
package/dist/esm/plugin.js
CHANGED
|
@@ -36,6 +36,48 @@ export var mediaInsertPlugin = function mediaInsertPlugin(_ref) {
|
|
|
36
36
|
popupsMountPoint = _ref3.popupsMountPoint,
|
|
37
37
|
popupsBoundariesElement = _ref3.popupsBoundariesElement,
|
|
38
38
|
popupsScrollableElement = _ref3.popupsScrollableElement;
|
|
39
|
+
var insertMediaSingle = function insertMediaSingle(_ref4) {
|
|
40
|
+
var _api$media$actions$in;
|
|
41
|
+
var mediaState = _ref4.mediaState,
|
|
42
|
+
inputMethod = _ref4.inputMethod;
|
|
43
|
+
var id = mediaState.id,
|
|
44
|
+
dimensions = mediaState.dimensions,
|
|
45
|
+
contextId = mediaState.contextId,
|
|
46
|
+
_mediaState$scaleFact = mediaState.scaleFactor,
|
|
47
|
+
scaleFactor = _mediaState$scaleFact === void 0 ? 1 : _mediaState$scaleFact,
|
|
48
|
+
fileName = mediaState.fileName,
|
|
49
|
+
collection = mediaState.collection;
|
|
50
|
+
var _ref5 = dimensions || {
|
|
51
|
+
height: undefined,
|
|
52
|
+
width: undefined
|
|
53
|
+
},
|
|
54
|
+
width = _ref5.width,
|
|
55
|
+
height = _ref5.height;
|
|
56
|
+
var scaledWidth = width && Math.round(width / scaleFactor);
|
|
57
|
+
var node = editorView.state.schema.nodes.media.create({
|
|
58
|
+
id: id,
|
|
59
|
+
type: 'file',
|
|
60
|
+
collection: collection,
|
|
61
|
+
contextId: contextId,
|
|
62
|
+
width: scaledWidth,
|
|
63
|
+
height: height && Math.round(height / scaleFactor),
|
|
64
|
+
alt: fileName,
|
|
65
|
+
__fileMimeType: mediaState.fileMimeType
|
|
66
|
+
});
|
|
67
|
+
return (_api$media$actions$in = api === null || api === void 0 ? void 0 : api.media.actions.insertMediaAsMediaSingle(editorView, node, inputMethod)) !== null && _api$media$actions$in !== void 0 ? _api$media$actions$in : false;
|
|
68
|
+
};
|
|
69
|
+
var insertExternalMediaSingle = function insertExternalMediaSingle(_ref6) {
|
|
70
|
+
var _api$media$actions$in2;
|
|
71
|
+
var url = _ref6.url,
|
|
72
|
+
alt = _ref6.alt,
|
|
73
|
+
inputMethod = _ref6.inputMethod;
|
|
74
|
+
var node = editorView.state.schema.nodes.media.create({
|
|
75
|
+
type: 'external',
|
|
76
|
+
url: url,
|
|
77
|
+
alt: alt
|
|
78
|
+
});
|
|
79
|
+
return (_api$media$actions$in2 = api === null || api === void 0 ? void 0 : api.media.actions.insertMediaAsMediaSingle(editorView, node, inputMethod)) !== null && _api$media$actions$in2 !== void 0 ? _api$media$actions$in2 : false;
|
|
80
|
+
};
|
|
39
81
|
return /*#__PURE__*/React.createElement(MediaInsertPicker, {
|
|
40
82
|
api: api,
|
|
41
83
|
editorView: editorView,
|
|
@@ -44,13 +86,15 @@ export var mediaInsertPlugin = function mediaInsertPlugin(_ref) {
|
|
|
44
86
|
popupsBoundariesElement: popupsBoundariesElement,
|
|
45
87
|
popupsScrollableElement: popupsScrollableElement,
|
|
46
88
|
closeMediaInsertPicker: function closeMediaInsertPicker() {
|
|
47
|
-
editorView.dispatch(_closeMediaInsertPicker(editorView.state.tr));
|
|
48
|
-
}
|
|
89
|
+
return editorView.dispatch(_closeMediaInsertPicker(editorView.state.tr));
|
|
90
|
+
},
|
|
91
|
+
insertMediaSingle: insertMediaSingle,
|
|
92
|
+
insertExternalMediaSingle: insertExternalMediaSingle
|
|
49
93
|
});
|
|
50
94
|
},
|
|
51
95
|
pluginsOptions: {
|
|
52
|
-
quickInsert: function quickInsert(
|
|
53
|
-
var formatMessage =
|
|
96
|
+
quickInsert: function quickInsert(_ref7) {
|
|
97
|
+
var formatMessage = _ref7.formatMessage;
|
|
54
98
|
return [{
|
|
55
99
|
id: 'media-insert',
|
|
56
100
|
title: formatMessage(messages.insertMediaFromUrl),
|
|
@@ -0,0 +1,136 @@
|
|
|
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 { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
9
|
+
import { mediaInsertMessages } from '@atlaskit/editor-common/messages';
|
|
10
|
+
import UploadIcon from '@atlaskit/icon/glyph/upload';
|
|
11
|
+
import { Browser } from '@atlaskit/media-picker';
|
|
12
|
+
import { Stack } from '@atlaskit/primitives';
|
|
13
|
+
import SectionMessage from '@atlaskit/section-message';
|
|
14
|
+
import { useAnalyticsEvents } from './useAnalyticsEvents';
|
|
15
|
+
var INITIAL_UPLOAD_STATE = Object.freeze({
|
|
16
|
+
isOpen: false,
|
|
17
|
+
error: null
|
|
18
|
+
});
|
|
19
|
+
var uploadReducer = function uploadReducer(state, action) {
|
|
20
|
+
switch (action.type) {
|
|
21
|
+
case 'open':
|
|
22
|
+
return _objectSpread(_objectSpread({}, INITIAL_UPLOAD_STATE), {}, {
|
|
23
|
+
isOpen: true
|
|
24
|
+
});
|
|
25
|
+
case 'close':
|
|
26
|
+
// This is the only case where we don't reset state. This is because
|
|
27
|
+
// onClose gets called for cancel _and_ upload, so we don't want to
|
|
28
|
+
// reset any loading or error states that may have occured
|
|
29
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
30
|
+
isOpen: false
|
|
31
|
+
});
|
|
32
|
+
case 'error':
|
|
33
|
+
return _objectSpread(_objectSpread({}, INITIAL_UPLOAD_STATE), {}, {
|
|
34
|
+
error: action.error
|
|
35
|
+
});
|
|
36
|
+
case 'reset':
|
|
37
|
+
return INITIAL_UPLOAD_STATE;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var isImagePreview = function isImagePreview(preview) {
|
|
41
|
+
return 'dimensions' in preview;
|
|
42
|
+
};
|
|
43
|
+
export var LocalMedia = function LocalMedia(_ref) {
|
|
44
|
+
var mediaProvider = _ref.mediaProvider,
|
|
45
|
+
onInsert = _ref.onInsert,
|
|
46
|
+
dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent;
|
|
47
|
+
var intl = useIntl();
|
|
48
|
+
var strings = {
|
|
49
|
+
upload: intl.formatMessage(mediaInsertMessages.upload),
|
|
50
|
+
networkError: intl.formatMessage(mediaInsertMessages.localFileNetworkErrorMessage),
|
|
51
|
+
genericError: intl.formatMessage(mediaInsertMessages.localFileErrorMessage)
|
|
52
|
+
};
|
|
53
|
+
var _useAnalyticsEvents = useAnalyticsEvents(dispatchAnalyticsEvent),
|
|
54
|
+
onUploadButtonClickedAnalytics = _useAnalyticsEvents.onUploadButtonClickedAnalytics,
|
|
55
|
+
onUploadCommencedAnalytics = _useAnalyticsEvents.onUploadCommencedAnalytics,
|
|
56
|
+
onUploadSuccessAnalytics = _useAnalyticsEvents.onUploadSuccessAnalytics,
|
|
57
|
+
onUploadFailureAnalytics = _useAnalyticsEvents.onUploadFailureAnalytics;
|
|
58
|
+
var _React$useReducer = React.useReducer(uploadReducer, INITIAL_UPLOAD_STATE),
|
|
59
|
+
_React$useReducer2 = _slicedToArray(_React$useReducer, 2),
|
|
60
|
+
uploadState = _React$useReducer2[0],
|
|
61
|
+
dispatch = _React$useReducer2[1];
|
|
62
|
+
var onUpload = function onUpload(_ref2) {
|
|
63
|
+
var _mediaProvider$upload;
|
|
64
|
+
var file = _ref2.file,
|
|
65
|
+
preview = _ref2.preview;
|
|
66
|
+
onUploadSuccessAnalytics('local');
|
|
67
|
+
var mediaState = {
|
|
68
|
+
id: file.id,
|
|
69
|
+
collection: (_mediaProvider$upload = mediaProvider.uploadParams) === null || _mediaProvider$upload === void 0 ? void 0 : _mediaProvider$upload.collection,
|
|
70
|
+
fileMimeType: file.type,
|
|
71
|
+
fileSize: file.size,
|
|
72
|
+
fileName: file.name,
|
|
73
|
+
dimensions: undefined
|
|
74
|
+
};
|
|
75
|
+
if (isImagePreview(preview)) {
|
|
76
|
+
mediaState.dimensions = {
|
|
77
|
+
width: preview.dimensions.width,
|
|
78
|
+
height: preview.dimensions.height
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
onInsert({
|
|
82
|
+
mediaState: mediaState,
|
|
83
|
+
inputMethod: INPUT_METHOD.MEDIA_PICKER
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Probably not needed but I guess it _could_ fail to close for some reason
|
|
87
|
+
dispatch({
|
|
88
|
+
type: 'reset'
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
var uploadParams = mediaProvider.uploadParams,
|
|
92
|
+
uploadMediaClientConfig = mediaProvider.uploadMediaClientConfig;
|
|
93
|
+
return /*#__PURE__*/React.createElement(Stack, {
|
|
94
|
+
grow: "fill",
|
|
95
|
+
space: "space.200"
|
|
96
|
+
}, uploadState.error && /*#__PURE__*/React.createElement(SectionMessage, {
|
|
97
|
+
appearance: "error"
|
|
98
|
+
}, uploadState.error === 'upload_fail' ? strings.networkError : strings.genericError), /*#__PURE__*/React.createElement(Button, {
|
|
99
|
+
iconBefore: UploadIcon,
|
|
100
|
+
shouldFitContainer: true,
|
|
101
|
+
isDisabled: !uploadMediaClientConfig || !uploadParams,
|
|
102
|
+
onClick: function onClick() {
|
|
103
|
+
onUploadButtonClickedAnalytics();
|
|
104
|
+
dispatch({
|
|
105
|
+
type: 'open'
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
autoFocus: true
|
|
109
|
+
}, strings.upload), uploadMediaClientConfig && uploadParams && /*#__PURE__*/React.createElement(Browser, {
|
|
110
|
+
isOpen: uploadState.isOpen,
|
|
111
|
+
config: {
|
|
112
|
+
uploadParams: uploadParams
|
|
113
|
+
},
|
|
114
|
+
mediaClientConfig: uploadMediaClientConfig,
|
|
115
|
+
onUploadsStart: function onUploadsStart() {
|
|
116
|
+
onUploadCommencedAnalytics('local');
|
|
117
|
+
},
|
|
118
|
+
onPreviewUpdate: onUpload
|
|
119
|
+
// NOTE: this will fire for some errors like network failures, but not
|
|
120
|
+
// for others like empty files. Those have their own feedback toast
|
|
121
|
+
// owned by media.
|
|
122
|
+
,
|
|
123
|
+
onError: function onError(payload) {
|
|
124
|
+
onUploadFailureAnalytics(payload.error.name, 'local');
|
|
125
|
+
dispatch({
|
|
126
|
+
type: 'error',
|
|
127
|
+
error: payload.error.name
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
onClose: function onClose() {
|
|
131
|
+
dispatch({
|
|
132
|
+
type: 'close'
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}));
|
|
136
|
+
};
|