@atlaskit/editor-core 187.28.1 → 187.28.3

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @atlaskit/editor-core
2
2
 
3
+ ## 187.28.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`6cced3b0ed6`](https://bitbucket.org/atlassian/atlassian-frontend/commits/6cced3b0ed6) - Warn if the emoji provider prop for the Editor is changing too quickly as it will cause performance issues.
8
+
9
+ ## 187.28.2
10
+
11
+ ### Patch Changes
12
+
13
+ - [`a3c9fd814c5`](https://bitbucket.org/atlassian/atlassian-frontend/commits/a3c9fd814c5) - Set minimum width for media single node of video type (when first inserted and when resizing)
14
+
3
15
  ## 187.28.1
4
16
 
5
17
  ### Patch Changes
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.ACTIONS = void 0;
8
8
  exports.createEmojiPlugin = createEmojiPlugin;
9
+ exports.createRateLimitReachedFunction = createRateLimitReachedFunction;
9
10
  exports.emojiToTypeaheadItem = exports.emojiPluginKey = exports.emojiPlugin = exports.defaultListLimit = void 0;
10
11
  exports.getEmojiPluginState = getEmojiPluginState;
11
12
  exports.memoize = memoize;
@@ -268,7 +269,44 @@ var setAsciiMap = function setAsciiMap(asciiMap) {
268
269
  return true;
269
270
  };
270
271
  };
271
- var setProvider = function setProvider(provider) {
272
+
273
+ /**
274
+ *
275
+ * Wrapper to call `onLimitReached` when a specified number of calls of that function
276
+ * have been made within a time period.
277
+ *
278
+ * Note: It does not rate limit
279
+ *
280
+ * @param fn Function to wrap
281
+ * @param limitTime Time limit in milliseconds
282
+ * @param limitCount Number of function calls before `onRateReached` is called (per time period)
283
+ * @returns Wrapped function
284
+ */
285
+ function createRateLimitReachedFunction(fn, limitTime, limitCount, onLimitReached) {
286
+ var lastCallTime = 0;
287
+ var callCount = 0;
288
+ return function wrappedFn() {
289
+ var now = Date.now();
290
+ if (now - lastCallTime < limitTime) {
291
+ if (++callCount > limitCount) {
292
+ onLimitReached === null || onLimitReached === void 0 ? void 0 : onLimitReached();
293
+ }
294
+ } else {
295
+ lastCallTime = now;
296
+ callCount = 1;
297
+ }
298
+ return fn.apply(void 0, arguments);
299
+ };
300
+ }
301
+
302
+ // At this stage console.error only
303
+ var logRateWarning = function logRateWarning() {
304
+ if (process.env.NODE_ENV === 'development') {
305
+ // eslint-disable-next-line no-console
306
+ console.error('The emoji provider injected in the Editor is being reloaded frequently, this will cause a slow Editor experience.');
307
+ }
308
+ };
309
+ var setProvider = createRateLimitReachedFunction(function (provider) {
272
310
  return function (state, dispatch) {
273
311
  if (dispatch) {
274
312
  dispatch(state.tr.setMeta(emojiPluginKey, {
@@ -280,7 +318,11 @@ var setProvider = function setProvider(provider) {
280
318
  }
281
319
  return true;
282
320
  };
283
- };
321
+ },
322
+ // If we change the emoji provider more than three times every 5 seconds we should warn.
323
+ // This seems like a really long time but the performance can be that laggy that we don't
324
+ // even get 3 events in 3 seconds and miss this indicator.
325
+ 5000, 3, logRateWarning);
284
326
  exports.setProvider = setProvider;
285
327
  var emojiPluginKey = new _state.PluginKey('emojiPlugin');
286
328
  exports.emojiPluginKey = emojiPluginKey;
@@ -335,15 +377,18 @@ function createEmojiPlugin(pmPluginFactoryParams) {
335
377
  switch (name) {
336
378
  case 'emojiProvider':
337
379
  if (!providerPromise) {
338
- return setProvider(undefined)(editorView.state, editorView.dispatch);
380
+ var _setProvider;
381
+ return setProvider === null || setProvider === void 0 ? void 0 : (_setProvider = setProvider(undefined)) === null || _setProvider === void 0 ? void 0 : _setProvider(editorView.state, editorView.dispatch);
339
382
  }
340
383
  providerPromise.then(function (provider) {
341
- setProvider(provider)(editorView.state, editorView.dispatch);
384
+ var _setProvider2;
385
+ setProvider === null || setProvider === void 0 ? void 0 : (_setProvider2 = setProvider(provider)) === null || _setProvider2 === void 0 ? void 0 : _setProvider2(editorView.state, editorView.dispatch);
342
386
  provider.getAsciiMap().then(function (asciiMap) {
343
387
  setAsciiMap(asciiMap)(editorView.state, editorView.dispatch);
344
388
  });
345
389
  }).catch(function () {
346
- return setProvider(undefined)(editorView.state, editorView.dispatch);
390
+ var _setProvider3;
391
+ return setProvider === null || setProvider === void 0 ? void 0 : (_setProvider3 = setProvider(undefined)) === null || _setProvider3 === void 0 ? void 0 : _setProvider3(editorView.state, editorView.dispatch);
347
392
  });
348
393
  break;
349
394
  }
@@ -303,7 +303,7 @@ var generateMediaSingleFloatingToolbar = function generateMediaSingleFloatingToo
303
303
  mediaWidth: mediaWidth || _mediaSingle.DEFAULT_IMAGE_WIDTH,
304
304
  mediaHeight: mediaHeight || _mediaSingle.DEFAULT_IMAGE_HEIGHT,
305
305
  validate: function validate(value) {
306
- if (value !== '' && !isNaN(value) && value >= _mediaSingle.MEDIA_SINGLE_MIN_PIXEL_WIDTH && value <= _editorSharedStyles.akEditorFullWidthLayoutWidth) {
306
+ if (value !== '' && !isNaN(value) && value >= _mediaSingle.MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH && value <= _editorSharedStyles.akEditorFullWidthLayoutWidth) {
307
307
  return true;
308
308
  }
309
309
  return false;
@@ -149,6 +149,9 @@ var ResizableMediaSingleNext = /*#__PURE__*/function (_React$Component) {
149
149
  }
150
150
  return (0, _mediaSingle.calcMediaSingleMaxWidth)(containerWidth);
151
151
  }));
152
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "calcMinWidth", (0, _memoizeOne.default)(function (isVideoFile, contentWidth) {
153
+ return Math.min(contentWidth || _editorSharedStyles.akEditorDefaultLayoutWidth, isVideoFile ? _mediaSingle.MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH : _mediaSingle.MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH);
154
+ }));
152
155
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getRelativeGuides", function () {
153
156
  var $pos = _this.$pos;
154
157
  var relativeGuides = $pos && $pos.nodeAfter && _this.state.size.width ? (0, _guideline.getRelativeGuidelines)(_this.state.relativeGuides, {
@@ -492,7 +495,8 @@ var ResizableMediaSingleNext = /*#__PURE__*/function (_React$Component) {
492
495
  lineLength = _this$props8.lineLength;
493
496
  var _this$state = this.state,
494
497
  isResizing = _this$state.isResizing,
495
- size = _this$state.size;
498
+ size = _this$state.size,
499
+ isVideoFile = _this$state.isVideoFile;
496
500
  var enable = {};
497
501
  _ui.handleSides.forEach(function (side) {
498
502
  var oppositeSide = side === 'left' ? 'right' : 'left';
@@ -510,6 +514,7 @@ var ResizableMediaSingleNext = /*#__PURE__*/function (_React$Component) {
510
514
  });
511
515
  var resizerNextClassName = (0, _classnames.default)(className, _styles.resizerStyles);
512
516
  var maxWidth = this.calcMaxWidth(lineLength, containerWidth, fullWidthMode);
517
+ var minWidth = this.calcMinWidth(isVideoFile, lineLength);
513
518
  return (0, _react2.jsx)("div", {
514
519
  ref: this.saveWrapper,
515
520
  css: (0, _styled.wrapperStyle)({
@@ -522,7 +527,7 @@ var ResizableMediaSingleNext = /*#__PURE__*/function (_React$Component) {
522
527
  isExtendedResizeExperienceOn: true
523
528
  })
524
529
  }, (0, _react2.jsx)(_resizer.ResizerNext, {
525
- minWidth: _mediaSingle.MEDIA_SINGLE_MIN_PIXEL_WIDTH,
530
+ minWidth: minWidth,
526
531
  maxWidth: maxWidth,
527
532
  className: resizerNextClassName,
528
533
  snapGap: _mediaSingle.MEDIA_SINGLE_SNAP_GAP,
@@ -6,14 +6,14 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.insertMediaSingleNode = exports.insertMediaAsMediaSingle = exports.getParentWidthForNestedMediaSingleNode = exports.createMediaSingleNode = void 0;
8
8
  exports.isCaptionNode = isCaptionNode;
9
- exports.isMediaSingle = void 0;
9
+ exports.isVideo = exports.isMediaSingle = void 0;
10
10
  exports.transformSliceForMedia = transformSliceForMedia;
11
11
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
12
12
  var _model = require("@atlaskit/editor-prosemirror/model");
13
13
  var _utils = require("@atlaskit/editor-prosemirror/utils");
14
14
  var _utils2 = require("../../../utils");
15
- var _utils3 = require("@atlaskit/editor-common/utils");
16
15
  var _mediaSingle = require("@atlaskit/editor-common/media-single");
16
+ var _utils3 = require("@atlaskit/editor-common/utils");
17
17
  var _mediaCommon = require("../utils/media-common");
18
18
  var _slice = require("../../../utils/slice");
19
19
  var _analytics = require("@atlaskit/editor-common/analytics");
@@ -104,9 +104,7 @@ var insertMediaSingleNode = function insertMediaSingleNode(view, mediaState, inp
104
104
  // add undefined as fallback as we don't want media single width to have upper limit as 0
105
105
  // if widthPluginState.width is 0, default 760 will be used
106
106
  var contentWidth = (widthPluginState === null || widthPluginState === void 0 ? void 0 : widthPluginState.lineLength) || (widthPluginState === null || widthPluginState === void 0 ? void 0 : widthPluginState.width) || undefined;
107
- var node = createMediaSingleNode(state.schema, collection, contentWidth,
108
- // pass undefined to use default min width
109
- undefined, alignLeftOnInsert)(mediaState);
107
+ var node = createMediaSingleNode(state.schema, collection, contentWidth, mediaState.status !== 'error' && isVideo(mediaState.fileMimeType) ? _mediaSingle.MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH : _mediaSingle.MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, alignLeftOnInsert)(mediaState);
110
108
  var fileExtension;
111
109
  if (mediaState.fileName) {
112
110
  var extensionIdx = mediaState.fileName.lastIndexOf('.');
@@ -224,6 +222,10 @@ function isCaptionNode(editorView) {
224
222
  }
225
223
  return false;
226
224
  }
225
+ var isVideo = function isVideo(fileType) {
226
+ return !!fileType && fileType.includes('video');
227
+ };
228
+ exports.isVideo = isVideo;
227
229
  var getParentWidthForNestedMediaSingleNode = function getParentWidthForNestedMediaSingleNode(resolvedPos, view) {
228
230
  var domNode = view.nodeDOM(resolvedPos.pos);
229
231
  if (resolvedPos.nodeAfter && _utils3.floatingLayouts.includes(resolvedPos.nodeAfter.attrs.layout) && domNode && domNode.parentElement) {
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.version = exports.nextMajorVersion = exports.name = void 0;
7
7
  var name = "@atlaskit/editor-core";
8
8
  exports.name = name;
9
- var version = "187.28.1";
9
+ var version = "187.28.3";
10
10
  exports.version = version;
11
11
  var nextMajorVersion = function nextMajorVersion() {
12
12
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
@@ -241,7 +241,44 @@ const setAsciiMap = asciiMap => (state, dispatch) => {
241
241
  }
242
242
  return true;
243
243
  };
244
- export const setProvider = provider => (state, dispatch) => {
244
+
245
+ /**
246
+ *
247
+ * Wrapper to call `onLimitReached` when a specified number of calls of that function
248
+ * have been made within a time period.
249
+ *
250
+ * Note: It does not rate limit
251
+ *
252
+ * @param fn Function to wrap
253
+ * @param limitTime Time limit in milliseconds
254
+ * @param limitCount Number of function calls before `onRateReached` is called (per time period)
255
+ * @returns Wrapped function
256
+ */
257
+ export function createRateLimitReachedFunction(fn, limitTime, limitCount, onLimitReached) {
258
+ let lastCallTime = 0;
259
+ let callCount = 0;
260
+ return function wrappedFn(...args) {
261
+ const now = Date.now();
262
+ if (now - lastCallTime < limitTime) {
263
+ if (++callCount > limitCount) {
264
+ onLimitReached === null || onLimitReached === void 0 ? void 0 : onLimitReached();
265
+ }
266
+ } else {
267
+ lastCallTime = now;
268
+ callCount = 1;
269
+ }
270
+ return fn(...args);
271
+ };
272
+ }
273
+
274
+ // At this stage console.error only
275
+ const logRateWarning = () => {
276
+ if (process.env.NODE_ENV === 'development') {
277
+ // eslint-disable-next-line no-console
278
+ console.error('The emoji provider injected in the Editor is being reloaded frequently, this will cause a slow Editor experience.');
279
+ }
280
+ };
281
+ export const setProvider = createRateLimitReachedFunction(provider => (state, dispatch) => {
245
282
  if (dispatch) {
246
283
  dispatch(state.tr.setMeta(emojiPluginKey, {
247
284
  action: ACTIONS.SET_PROVIDER,
@@ -251,7 +288,11 @@ export const setProvider = provider => (state, dispatch) => {
251
288
  }));
252
289
  }
253
290
  return true;
254
- };
291
+ },
292
+ // If we change the emoji provider more than three times every 5 seconds we should warn.
293
+ // This seems like a really long time but the performance can be that laggy that we don't
294
+ // even get 3 events in 3 seconds and miss this indicator.
295
+ 5000, 3, logRateWarning);
255
296
  export const emojiPluginKey = new PluginKey('emojiPlugin');
256
297
  export function getEmojiPluginState(state) {
257
298
  return emojiPluginKey.getState(state) || {};
@@ -307,14 +348,19 @@ export function createEmojiPlugin(pmPluginFactoryParams) {
307
348
  switch (name) {
308
349
  case 'emojiProvider':
309
350
  if (!providerPromise) {
310
- return setProvider(undefined)(editorView.state, editorView.dispatch);
351
+ var _setProvider;
352
+ return setProvider === null || setProvider === void 0 ? void 0 : (_setProvider = setProvider(undefined)) === null || _setProvider === void 0 ? void 0 : _setProvider(editorView.state, editorView.dispatch);
311
353
  }
312
354
  providerPromise.then(provider => {
313
- setProvider(provider)(editorView.state, editorView.dispatch);
355
+ var _setProvider2;
356
+ setProvider === null || setProvider === void 0 ? void 0 : (_setProvider2 = setProvider(provider)) === null || _setProvider2 === void 0 ? void 0 : _setProvider2(editorView.state, editorView.dispatch);
314
357
  provider.getAsciiMap().then(asciiMap => {
315
358
  setAsciiMap(asciiMap)(editorView.state, editorView.dispatch);
316
359
  });
317
- }).catch(() => setProvider(undefined)(editorView.state, editorView.dispatch));
360
+ }).catch(() => {
361
+ var _setProvider3;
362
+ return setProvider === null || setProvider === void 0 ? void 0 : (_setProvider3 = setProvider(undefined)) === null || _setProvider3 === void 0 ? void 0 : _setProvider3(editorView.state, editorView.dispatch);
363
+ });
318
364
  break;
319
365
  }
320
366
  return;
@@ -25,7 +25,7 @@ import ImageBorderItem from '../ui/ImageBorder';
25
25
  import { currentMediaNodeBorderMark } from '../utils/current-media-node';
26
26
  import { shouldShowImageBorder } from './imageBorder';
27
27
  import { PixelEntry } from '../ui/PixelEntry';
28
- import { DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, MEDIA_SINGLE_MIN_PIXEL_WIDTH, MEDIA_SINGLE_GUTTER_SIZE, calcMediaSinglePixelWidth } from '@atlaskit/editor-common/media-single';
28
+ import { DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, MEDIA_SINGLE_GUTTER_SIZE, calcMediaSinglePixelWidth } from '@atlaskit/editor-common/media-single';
29
29
  import { akEditorDefaultLayoutWidth, akEditorFullWidthLayoutWidth } from '@atlaskit/editor-shared-styles';
30
30
  const remove = (state, dispatch) => {
31
31
  if (dispatch) {
@@ -308,7 +308,7 @@ const generateMediaSingleFloatingToolbar = (state, intl, options, pluginState, m
308
308
  mediaWidth: mediaWidth || DEFAULT_IMAGE_WIDTH,
309
309
  mediaHeight: mediaHeight || DEFAULT_IMAGE_HEIGHT,
310
310
  validate: value => {
311
- if (value !== '' && !isNaN(value) && value >= MEDIA_SINGLE_MIN_PIXEL_WIDTH && value <= akEditorFullWidthLayoutWidth) {
311
+ if (value !== '' && !isNaN(value) && value >= MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH && value <= akEditorFullWidthLayoutWidth) {
312
312
  return true;
313
313
  }
314
314
  return false;
@@ -6,12 +6,12 @@ import { findParentNodeOfTypeClosestToPos, hasParentNodeOfType } from '@atlaskit
6
6
  import { getMediaClient } from '@atlaskit/media-client';
7
7
  import { calcPctFromPx, wrappedLayouts, handleSides, imageAlignmentMap } from '@atlaskit/editor-common/ui';
8
8
  import { nonWrappedLayouts, setNodeSelection } from '@atlaskit/editor-common/utils';
9
- import { akEditorFullWidthLayoutWidth, akEditorGutterPadding } from '@atlaskit/editor-shared-styles';
9
+ import { akEditorFullWidthLayoutWidth, akEditorGutterPadding, akEditorDefaultLayoutWidth } from '@atlaskit/editor-shared-styles';
10
10
  import { wrapperStyle } from './styled';
11
11
  import { ResizerNext } from '@atlaskit/editor-common/resizer';
12
12
  import classnames from 'classnames';
13
13
  import { richMediaClassName, resizerStyles } from '@atlaskit/editor-common/styles';
14
- import { MEDIA_SINGLE_MIN_PIXEL_WIDTH, MEDIA_SINGLE_SNAP_GAP, MEDIA_SINGLE_RESIZE_THROTTLE_TIME, calculateOffsetLeft, DEFAULT_IMAGE_WIDTH, calcMediaSingleMaxWidth } from '@atlaskit/editor-common/media-single';
14
+ import { MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH, MEDIA_SINGLE_SNAP_GAP, MEDIA_SINGLE_RESIZE_THROTTLE_TIME, calculateOffsetLeft, DEFAULT_IMAGE_WIDTH, calcMediaSingleMaxWidth } from '@atlaskit/editor-common/media-single';
15
15
  import { findClosestSnap, getGuidelinesWithHighlights, generateDefaultGuidelines, generateDynamicGuidelines, getGuidelineSnaps, getGuidelineTypeFromKey, getRelativeGuideSnaps, getRelativeGuidelines } from '@atlaskit/editor-common/guideline';
16
16
  import memoizeOne from 'memoize-one';
17
17
  import { getMediaResizeAnalyticsEvent } from '../../utils/analytics';
@@ -132,6 +132,9 @@ class ResizableMediaSingleNext extends React.Component {
132
132
  }
133
133
  return calcMediaSingleMaxWidth(containerWidth);
134
134
  }));
135
+ _defineProperty(this, "calcMinWidth", memoizeOne((isVideoFile, contentWidth) => {
136
+ return Math.min(contentWidth || akEditorDefaultLayoutWidth, isVideoFile ? MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH : MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH);
137
+ }));
135
138
  _defineProperty(this, "getRelativeGuides", () => {
136
139
  const $pos = this.$pos;
137
140
  const relativeGuides = $pos && $pos.nodeAfter && this.state.size.width ? getRelativeGuidelines(this.state.relativeGuides, {
@@ -411,7 +414,8 @@ class ResizableMediaSingleNext extends React.Component {
411
414
  } = this.props;
412
415
  const {
413
416
  isResizing,
414
- size
417
+ size,
418
+ isVideoFile
415
419
  } = this.state;
416
420
  const enable = {};
417
421
  handleSides.forEach(side => {
@@ -430,6 +434,7 @@ class ResizableMediaSingleNext extends React.Component {
430
434
  });
431
435
  const resizerNextClassName = classnames(className, resizerStyles);
432
436
  const maxWidth = this.calcMaxWidth(lineLength, containerWidth, fullWidthMode);
437
+ const minWidth = this.calcMinWidth(isVideoFile, lineLength);
433
438
  return jsx("div", {
434
439
  ref: this.saveWrapper,
435
440
  css: wrapperStyle({
@@ -442,7 +447,7 @@ class ResizableMediaSingleNext extends React.Component {
442
447
  isExtendedResizeExperienceOn: true
443
448
  })
444
449
  }, jsx(ResizerNext, {
445
- minWidth: MEDIA_SINGLE_MIN_PIXEL_WIDTH,
450
+ minWidth: minWidth,
446
451
  maxWidth: maxWidth,
447
452
  className: resizerNextClassName,
448
453
  snapGap: MEDIA_SINGLE_SNAP_GAP,
@@ -1,8 +1,8 @@
1
1
  import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
2
2
  import { safeInsert as pmSafeInsert, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
3
3
  import { checkNodeDown } from '../../../utils';
4
+ import { getMediaSingleInitialWidth, MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH } from '@atlaskit/editor-common/media-single';
4
5
  import { isEmptyParagraph, floatingLayouts } from '@atlaskit/editor-common/utils';
5
- import { getMediaSingleInitialWidth } from '@atlaskit/editor-common/media-single';
6
6
  import { copyOptionalAttrsFromMediaState } from '../utils/media-common';
7
7
  import { mapSlice } from '../../../utils/slice';
8
8
  import { ACTION, ACTION_SUBJECT, EVENT_TYPE, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
@@ -94,9 +94,7 @@ export const insertMediaSingleNode = (view, mediaState, inputMethod, collection,
94
94
  // add undefined as fallback as we don't want media single width to have upper limit as 0
95
95
  // if widthPluginState.width is 0, default 760 will be used
96
96
  const contentWidth = (widthPluginState === null || widthPluginState === void 0 ? void 0 : widthPluginState.lineLength) || (widthPluginState === null || widthPluginState === void 0 ? void 0 : widthPluginState.width) || undefined;
97
- const node = createMediaSingleNode(state.schema, collection, contentWidth,
98
- // pass undefined to use default min width
99
- undefined, alignLeftOnInsert)(mediaState);
97
+ const node = createMediaSingleNode(state.schema, collection, contentWidth, mediaState.status !== 'error' && isVideo(mediaState.fileMimeType) ? MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH : MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, alignLeftOnInsert)(mediaState);
100
98
  let fileExtension;
101
99
  if (mediaState.fileName) {
102
100
  const extensionIdx = mediaState.fileName.lastIndexOf('.');
@@ -219,6 +217,7 @@ export function isCaptionNode(editorView) {
219
217
  }
220
218
  return false;
221
219
  }
220
+ export const isVideo = fileType => !!fileType && fileType.includes('video');
222
221
  export const getParentWidthForNestedMediaSingleNode = (resolvedPos, view) => {
223
222
  const domNode = view.nodeDOM(resolvedPos.pos);
224
223
  if (resolvedPos.nodeAfter && floatingLayouts.includes(resolvedPos.nodeAfter.attrs.layout) && domNode && domNode.parentElement) {
@@ -1,5 +1,5 @@
1
1
  export const name = "@atlaskit/editor-core";
2
- export const version = "187.28.1";
2
+ export const version = "187.28.3";
3
3
  export const nextMajorVersion = () => {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -253,7 +253,44 @@ var setAsciiMap = function setAsciiMap(asciiMap) {
253
253
  return true;
254
254
  };
255
255
  };
256
- export var setProvider = function setProvider(provider) {
256
+
257
+ /**
258
+ *
259
+ * Wrapper to call `onLimitReached` when a specified number of calls of that function
260
+ * have been made within a time period.
261
+ *
262
+ * Note: It does not rate limit
263
+ *
264
+ * @param fn Function to wrap
265
+ * @param limitTime Time limit in milliseconds
266
+ * @param limitCount Number of function calls before `onRateReached` is called (per time period)
267
+ * @returns Wrapped function
268
+ */
269
+ export function createRateLimitReachedFunction(fn, limitTime, limitCount, onLimitReached) {
270
+ var lastCallTime = 0;
271
+ var callCount = 0;
272
+ return function wrappedFn() {
273
+ var now = Date.now();
274
+ if (now - lastCallTime < limitTime) {
275
+ if (++callCount > limitCount) {
276
+ onLimitReached === null || onLimitReached === void 0 ? void 0 : onLimitReached();
277
+ }
278
+ } else {
279
+ lastCallTime = now;
280
+ callCount = 1;
281
+ }
282
+ return fn.apply(void 0, arguments);
283
+ };
284
+ }
285
+
286
+ // At this stage console.error only
287
+ var logRateWarning = function logRateWarning() {
288
+ if (process.env.NODE_ENV === 'development') {
289
+ // eslint-disable-next-line no-console
290
+ console.error('The emoji provider injected in the Editor is being reloaded frequently, this will cause a slow Editor experience.');
291
+ }
292
+ };
293
+ export var setProvider = createRateLimitReachedFunction(function (provider) {
257
294
  return function (state, dispatch) {
258
295
  if (dispatch) {
259
296
  dispatch(state.tr.setMeta(emojiPluginKey, {
@@ -265,7 +302,11 @@ export var setProvider = function setProvider(provider) {
265
302
  }
266
303
  return true;
267
304
  };
268
- };
305
+ },
306
+ // If we change the emoji provider more than three times every 5 seconds we should warn.
307
+ // This seems like a really long time but the performance can be that laggy that we don't
308
+ // even get 3 events in 3 seconds and miss this indicator.
309
+ 5000, 3, logRateWarning);
269
310
  export var emojiPluginKey = new PluginKey('emojiPlugin');
270
311
  export function getEmojiPluginState(state) {
271
312
  return emojiPluginKey.getState(state) || {};
@@ -318,15 +359,18 @@ export function createEmojiPlugin(pmPluginFactoryParams) {
318
359
  switch (name) {
319
360
  case 'emojiProvider':
320
361
  if (!providerPromise) {
321
- return setProvider(undefined)(editorView.state, editorView.dispatch);
362
+ var _setProvider;
363
+ return setProvider === null || setProvider === void 0 ? void 0 : (_setProvider = setProvider(undefined)) === null || _setProvider === void 0 ? void 0 : _setProvider(editorView.state, editorView.dispatch);
322
364
  }
323
365
  providerPromise.then(function (provider) {
324
- setProvider(provider)(editorView.state, editorView.dispatch);
366
+ var _setProvider2;
367
+ setProvider === null || setProvider === void 0 ? void 0 : (_setProvider2 = setProvider(provider)) === null || _setProvider2 === void 0 ? void 0 : _setProvider2(editorView.state, editorView.dispatch);
325
368
  provider.getAsciiMap().then(function (asciiMap) {
326
369
  setAsciiMap(asciiMap)(editorView.state, editorView.dispatch);
327
370
  });
328
371
  }).catch(function () {
329
- return setProvider(undefined)(editorView.state, editorView.dispatch);
372
+ var _setProvider3;
373
+ return setProvider === null || setProvider === void 0 ? void 0 : (_setProvider3 = setProvider(undefined)) === null || _setProvider3 === void 0 ? void 0 : _setProvider3(editorView.state, editorView.dispatch);
330
374
  });
331
375
  break;
332
376
  }
@@ -29,7 +29,7 @@ import ImageBorderItem from '../ui/ImageBorder';
29
29
  import { currentMediaNodeBorderMark } from '../utils/current-media-node';
30
30
  import { shouldShowImageBorder } from './imageBorder';
31
31
  import { PixelEntry } from '../ui/PixelEntry';
32
- import { DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, MEDIA_SINGLE_MIN_PIXEL_WIDTH, MEDIA_SINGLE_GUTTER_SIZE, calcMediaSinglePixelWidth } from '@atlaskit/editor-common/media-single';
32
+ import { DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, MEDIA_SINGLE_GUTTER_SIZE, calcMediaSinglePixelWidth } from '@atlaskit/editor-common/media-single';
33
33
  import { akEditorDefaultLayoutWidth, akEditorFullWidthLayoutWidth } from '@atlaskit/editor-shared-styles';
34
34
  var remove = function remove(state, dispatch) {
35
35
  if (dispatch) {
@@ -296,7 +296,7 @@ var generateMediaSingleFloatingToolbar = function generateMediaSingleFloatingToo
296
296
  mediaWidth: mediaWidth || DEFAULT_IMAGE_WIDTH,
297
297
  mediaHeight: mediaHeight || DEFAULT_IMAGE_HEIGHT,
298
298
  validate: function validate(value) {
299
- if (value !== '' && !isNaN(value) && value >= MEDIA_SINGLE_MIN_PIXEL_WIDTH && value <= akEditorFullWidthLayoutWidth) {
299
+ if (value !== '' && !isNaN(value) && value >= MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH && value <= akEditorFullWidthLayoutWidth) {
300
300
  return true;
301
301
  }
302
302
  return false;
@@ -17,12 +17,12 @@ import { findParentNodeOfTypeClosestToPos, hasParentNodeOfType } from '@atlaskit
17
17
  import { getMediaClient } from '@atlaskit/media-client';
18
18
  import { calcPctFromPx, wrappedLayouts, handleSides, imageAlignmentMap } from '@atlaskit/editor-common/ui';
19
19
  import { nonWrappedLayouts, setNodeSelection } from '@atlaskit/editor-common/utils';
20
- import { akEditorFullWidthLayoutWidth, akEditorGutterPadding } from '@atlaskit/editor-shared-styles';
20
+ import { akEditorFullWidthLayoutWidth, akEditorGutterPadding, akEditorDefaultLayoutWidth } from '@atlaskit/editor-shared-styles';
21
21
  import { wrapperStyle } from './styled';
22
22
  import { ResizerNext } from '@atlaskit/editor-common/resizer';
23
23
  import classnames from 'classnames';
24
24
  import { richMediaClassName, resizerStyles } from '@atlaskit/editor-common/styles';
25
- import { MEDIA_SINGLE_MIN_PIXEL_WIDTH, MEDIA_SINGLE_SNAP_GAP, MEDIA_SINGLE_RESIZE_THROTTLE_TIME, calculateOffsetLeft, DEFAULT_IMAGE_WIDTH, calcMediaSingleMaxWidth } from '@atlaskit/editor-common/media-single';
25
+ import { MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH, MEDIA_SINGLE_SNAP_GAP, MEDIA_SINGLE_RESIZE_THROTTLE_TIME, calculateOffsetLeft, DEFAULT_IMAGE_WIDTH, calcMediaSingleMaxWidth } from '@atlaskit/editor-common/media-single';
26
26
  import { findClosestSnap, getGuidelinesWithHighlights, generateDefaultGuidelines, generateDynamicGuidelines, getGuidelineSnaps, getGuidelineTypeFromKey, getRelativeGuideSnaps, getRelativeGuidelines } from '@atlaskit/editor-common/guideline';
27
27
  import memoizeOne from 'memoize-one';
28
28
  import { getMediaResizeAnalyticsEvent } from '../../utils/analytics';
@@ -142,6 +142,9 @@ var ResizableMediaSingleNext = /*#__PURE__*/function (_React$Component) {
142
142
  }
143
143
  return calcMediaSingleMaxWidth(containerWidth);
144
144
  }));
145
+ _defineProperty(_assertThisInitialized(_this), "calcMinWidth", memoizeOne(function (isVideoFile, contentWidth) {
146
+ return Math.min(contentWidth || akEditorDefaultLayoutWidth, isVideoFile ? MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH : MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH);
147
+ }));
145
148
  _defineProperty(_assertThisInitialized(_this), "getRelativeGuides", function () {
146
149
  var $pos = _this.$pos;
147
150
  var relativeGuides = $pos && $pos.nodeAfter && _this.state.size.width ? getRelativeGuidelines(_this.state.relativeGuides, {
@@ -485,7 +488,8 @@ var ResizableMediaSingleNext = /*#__PURE__*/function (_React$Component) {
485
488
  lineLength = _this$props8.lineLength;
486
489
  var _this$state = this.state,
487
490
  isResizing = _this$state.isResizing,
488
- size = _this$state.size;
491
+ size = _this$state.size,
492
+ isVideoFile = _this$state.isVideoFile;
489
493
  var enable = {};
490
494
  handleSides.forEach(function (side) {
491
495
  var oppositeSide = side === 'left' ? 'right' : 'left';
@@ -503,6 +507,7 @@ var ResizableMediaSingleNext = /*#__PURE__*/function (_React$Component) {
503
507
  });
504
508
  var resizerNextClassName = classnames(className, resizerStyles);
505
509
  var maxWidth = this.calcMaxWidth(lineLength, containerWidth, fullWidthMode);
510
+ var minWidth = this.calcMinWidth(isVideoFile, lineLength);
506
511
  return jsx("div", {
507
512
  ref: this.saveWrapper,
508
513
  css: wrapperStyle({
@@ -515,7 +520,7 @@ var ResizableMediaSingleNext = /*#__PURE__*/function (_React$Component) {
515
520
  isExtendedResizeExperienceOn: true
516
521
  })
517
522
  }, jsx(ResizerNext, {
518
- minWidth: MEDIA_SINGLE_MIN_PIXEL_WIDTH,
523
+ minWidth: minWidth,
519
524
  maxWidth: maxWidth,
520
525
  className: resizerNextClassName,
521
526
  snapGap: MEDIA_SINGLE_SNAP_GAP,
@@ -4,8 +4,8 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
4
4
  import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
5
5
  import { safeInsert as pmSafeInsert, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
6
6
  import { checkNodeDown } from '../../../utils';
7
+ import { getMediaSingleInitialWidth, MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH } from '@atlaskit/editor-common/media-single';
7
8
  import { isEmptyParagraph, floatingLayouts } from '@atlaskit/editor-common/utils';
8
- import { getMediaSingleInitialWidth } from '@atlaskit/editor-common/media-single';
9
9
  import { copyOptionalAttrsFromMediaState } from '../utils/media-common';
10
10
  import { mapSlice } from '../../../utils/slice';
11
11
  import { ACTION, ACTION_SUBJECT, EVENT_TYPE, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
@@ -92,9 +92,7 @@ export var insertMediaSingleNode = function insertMediaSingleNode(view, mediaSta
92
92
  // add undefined as fallback as we don't want media single width to have upper limit as 0
93
93
  // if widthPluginState.width is 0, default 760 will be used
94
94
  var contentWidth = (widthPluginState === null || widthPluginState === void 0 ? void 0 : widthPluginState.lineLength) || (widthPluginState === null || widthPluginState === void 0 ? void 0 : widthPluginState.width) || undefined;
95
- var node = createMediaSingleNode(state.schema, collection, contentWidth,
96
- // pass undefined to use default min width
97
- undefined, alignLeftOnInsert)(mediaState);
95
+ var node = createMediaSingleNode(state.schema, collection, contentWidth, mediaState.status !== 'error' && isVideo(mediaState.fileMimeType) ? MEDIA_SINGLE_VIDEO_MIN_PIXEL_WIDTH : MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH, alignLeftOnInsert)(mediaState);
98
96
  var fileExtension;
99
97
  if (mediaState.fileName) {
100
98
  var extensionIdx = mediaState.fileName.lastIndexOf('.');
@@ -210,6 +208,9 @@ export function isCaptionNode(editorView) {
210
208
  }
211
209
  return false;
212
210
  }
211
+ export var isVideo = function isVideo(fileType) {
212
+ return !!fileType && fileType.includes('video');
213
+ };
213
214
  export var getParentWidthForNestedMediaSingleNode = function getParentWidthForNestedMediaSingleNode(resolvedPos, view) {
214
215
  var domNode = view.nodeDOM(resolvedPos.pos);
215
216
  if (resolvedPos.nodeAfter && floatingLayouts.includes(resolvedPos.nodeAfter.attrs.layout) && domNode && domNode.parentElement) {
@@ -1,5 +1,5 @@
1
1
  export var name = "@atlaskit/editor-core";
2
- export var version = "187.28.1";
2
+ export var version = "187.28.3";
3
3
  export var nextMajorVersion = function nextMajorVersion() {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -31,7 +31,20 @@ export declare const ACTIONS: {
31
31
  SET_RESULTS: string;
32
32
  SET_ASCII_MAP: string;
33
33
  };
34
- export declare const setProvider: (provider?: EmojiProvider) => Command;
34
+ /**
35
+ *
36
+ * Wrapper to call `onLimitReached` when a specified number of calls of that function
37
+ * have been made within a time period.
38
+ *
39
+ * Note: It does not rate limit
40
+ *
41
+ * @param fn Function to wrap
42
+ * @param limitTime Time limit in milliseconds
43
+ * @param limitCount Number of function calls before `onRateReached` is called (per time period)
44
+ * @returns Wrapped function
45
+ */
46
+ export declare function createRateLimitReachedFunction<LimitedFunction extends (...args: any[]) => any>(fn: Function, limitTime: number, limitCount: number, onLimitReached: () => void): (...args: Parameters<LimitedFunction>) => ReturnType<LimitedFunction> | undefined;
47
+ export declare const setProvider: ((provider?: EmojiProvider) => Command) | undefined;
35
48
  export declare const emojiPluginKey: PluginKey<EmojiPluginState>;
36
49
  export declare function getEmojiPluginState(state: EditorState): EmojiPluginState;
37
50
  export declare function createEmojiPlugin(pmPluginFactoryParams: PMPluginFactoryParams): SafePlugin<EmojiPluginState>;
@@ -46,6 +46,7 @@ declare class ResizableMediaSingleNext extends React.Component<ResizableMediaSin
46
46
  private setIsResizing;
47
47
  private updateSizeInPluginState;
48
48
  private calcMaxWidth;
49
+ private calcMinWidth;
49
50
  private getRelativeGuides;
50
51
  updateActiveGuidelines: (width: number | undefined, guidelines: GuidelineConfig[], guidelineSnapsReference: GuidelineSnapsReference) => void;
51
52
  calculateSizeState: (size: Position & Dimensions, delta: Dimensions, onResizeStop?: boolean) => {
@@ -19,4 +19,5 @@ export declare const insertMediaSingleNode: (view: EditorView, mediaState: Media
19
19
  export declare const createMediaSingleNode: (schema: Schema, collection: string, maxWidth?: number, minWidth?: number, alignLeftOnInsert?: boolean) => (mediaState: MediaSingleState) => PMNode;
20
20
  export declare function transformSliceForMedia(slice: Slice, schema: Schema): (selection: Selection) => Slice;
21
21
  export declare function isCaptionNode(editorView: EditorView): boolean;
22
+ export declare const isVideo: (fileType?: string) => boolean;
22
23
  export declare const getParentWidthForNestedMediaSingleNode: (resolvedPos: ResolvedPos, view: EditorView) => number | null;
@@ -34,7 +34,20 @@ export declare const ACTIONS: {
34
34
  SET_RESULTS: string;
35
35
  SET_ASCII_MAP: string;
36
36
  };
37
- export declare const setProvider: (provider?: EmojiProvider) => Command;
37
+ /**
38
+ *
39
+ * Wrapper to call `onLimitReached` when a specified number of calls of that function
40
+ * have been made within a time period.
41
+ *
42
+ * Note: It does not rate limit
43
+ *
44
+ * @param fn Function to wrap
45
+ * @param limitTime Time limit in milliseconds
46
+ * @param limitCount Number of function calls before `onRateReached` is called (per time period)
47
+ * @returns Wrapped function
48
+ */
49
+ export declare function createRateLimitReachedFunction<LimitedFunction extends (...args: any[]) => any>(fn: Function, limitTime: number, limitCount: number, onLimitReached: () => void): (...args: Parameters<LimitedFunction>) => ReturnType<LimitedFunction> | undefined;
50
+ export declare const setProvider: ((provider?: EmojiProvider) => Command) | undefined;
38
51
  export declare const emojiPluginKey: PluginKey<EmojiPluginState>;
39
52
  export declare function getEmojiPluginState(state: EditorState): EmojiPluginState;
40
53
  export declare function createEmojiPlugin(pmPluginFactoryParams: PMPluginFactoryParams): SafePlugin<EmojiPluginState>;
@@ -46,6 +46,7 @@ declare class ResizableMediaSingleNext extends React.Component<ResizableMediaSin
46
46
  private setIsResizing;
47
47
  private updateSizeInPluginState;
48
48
  private calcMaxWidth;
49
+ private calcMinWidth;
49
50
  private getRelativeGuides;
50
51
  updateActiveGuidelines: (width: number | undefined, guidelines: GuidelineConfig[], guidelineSnapsReference: GuidelineSnapsReference) => void;
51
52
  calculateSizeState: (size: Position & Dimensions, delta: Dimensions, onResizeStop?: boolean) => {
@@ -19,4 +19,5 @@ export declare const insertMediaSingleNode: (view: EditorView, mediaState: Media
19
19
  export declare const createMediaSingleNode: (schema: Schema, collection: string, maxWidth?: number, minWidth?: number, alignLeftOnInsert?: boolean) => (mediaState: MediaSingleState) => PMNode;
20
20
  export declare function transformSliceForMedia(slice: Slice, schema: Schema): (selection: Selection) => Slice;
21
21
  export declare function isCaptionNode(editorView: EditorView): boolean;
22
+ export declare const isVideo: (fileType?: string) => boolean;
22
23
  export declare const getParentWidthForNestedMediaSingleNode: (resolvedPos: ResolvedPos, view: EditorView) => number | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-core",
3
- "version": "187.28.1",
3
+ "version": "187.28.3",
4
4
  "description": "A package contains Atlassian editor core functionality",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"