@atlaskit/editor-plugin-synced-block 5.3.32 → 5.3.34

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.
@@ -1,3 +1,5 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
+ import _createClass from "@babel/runtime/helpers/createClass";
1
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
4
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
5
  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; }
@@ -23,7 +25,7 @@ import { handleBodiedSyncBlockRemoval } from './utils/handle-bodied-sync-block-r
23
25
  import { shouldIgnoreDomEvent } from './utils/ignore-dom-event';
24
26
  import { calculateDecorations } from './utils/selection-decorations';
25
27
  import { hasEditInSyncBlock, trackSyncBlocks } from './utils/track-sync-blocks';
26
- import { wasInlineExtensionInsertedInBodiedSyncBlock, sliceFullyContainsNode } from './utils/utils';
28
+ import { deferDispatch, wasInlineExtensionInsertedInBodiedSyncBlock, sliceFullyContainsNode } from './utils/utils';
27
29
  export var syncedBlockPluginKey = new PluginKey('syncedBlockPlugin');
28
30
  var mapRetryCreationPosMap = function mapRetryCreationPosMap(oldMap, newRetryCreationPos, mapPos) {
29
31
  var resourceId = newRetryCreationPos === null || newRetryCreationPos === void 0 ? void 0 : newRetryCreationPos.resourceId;
@@ -59,8 +61,7 @@ var mapRetryCreationPosMap = function mapRetryCreationPosMap(oldMap, newRetryCre
59
61
  return newMap;
60
62
  };
61
63
  var showCopiedFlag = function showCopiedFlag(api) {
62
- // Use setTimeout to dispatch transaction in next tick and avoid re-entrant dispatch
63
- setTimeout(function () {
64
+ deferDispatch(function () {
64
65
  api === null || api === void 0 || api.core.actions.execute(function (_ref) {
65
66
  var tr = _ref.tr;
66
67
  return tr.setMeta(syncedBlockPluginKey, {
@@ -69,7 +70,7 @@ var showCopiedFlag = function showCopiedFlag(api) {
69
70
  }
70
71
  });
71
72
  });
72
- }, 0);
73
+ });
73
74
  };
74
75
  var showInlineExtensionInSyncBlockWarningIfNeeded = function showInlineExtensionInSyncBlockWarningIfNeeded(tr, state, api, inlineExtensionFlagShown) {
75
76
  var _api$connectivity;
@@ -83,8 +84,7 @@ var showInlineExtensionInSyncBlockWarningIfNeeded = function showInlineExtension
83
84
  // Only show the flag on the first instance per sync block (same as UNPUBLISHED_SYNC_BLOCK_PASTED)
84
85
  if (resourceId && !inlineExtensionFlagShown.has(resourceId)) {
85
86
  inlineExtensionFlagShown.add(resourceId);
86
- // Use setTimeout to dispatch in next tick and avoid re-entrant dispatch from filterTransaction
87
- setTimeout(function () {
87
+ deferDispatch(function () {
88
88
  api === null || api === void 0 || api.core.actions.execute(function (_ref2) {
89
89
  var tr = _ref2.tr;
90
90
  return tr.setMeta(syncedBlockPluginKey, {
@@ -93,7 +93,7 @@ var showInlineExtensionInSyncBlockWarningIfNeeded = function showInlineExtension
93
93
  }
94
94
  });
95
95
  });
96
- }, 0);
96
+ });
97
97
  }
98
98
  };
99
99
  var getDeleteReason = function getDeleteReason(tr) {
@@ -103,36 +103,176 @@ var getDeleteReason = function getDeleteReason(tr) {
103
103
  }
104
104
  return reason;
105
105
  };
106
+ var filterTransactionOnline = function filterTransactionOnline(_ref3) {
107
+ var tr = _ref3.tr,
108
+ state = _ref3.state,
109
+ syncBlockStore = _ref3.syncBlockStore,
110
+ api = _ref3.api,
111
+ confirmationTransactionRef = _ref3.confirmationTransactionRef,
112
+ bodiedSyncBlockRemoved = _ref3.bodiedSyncBlockRemoved,
113
+ bodiedSyncBlockAdded = _ref3.bodiedSyncBlockAdded,
114
+ inlineExtensionFlagShown = _ref3.inlineExtensionFlagShown;
115
+ var _trackSyncBlocks = trackSyncBlocks(function (node) {
116
+ return node.type.name === 'syncBlock';
117
+ }, tr, state),
118
+ syncBlockRemoved = _trackSyncBlocks.removed,
119
+ syncBlockAdded = _trackSyncBlocks.added;
120
+ syncBlockRemoved.forEach(function (syncBlock) {
121
+ var _api$analytics;
122
+ api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 || _api$analytics.fireAnalyticsEvent({
123
+ action: ACTION.DELETED,
124
+ actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
125
+ actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_DELETE,
126
+ attributes: {
127
+ resourceId: syncBlock.attrs.resourceId,
128
+ blockInstanceId: syncBlock.attrs.localId
129
+ },
130
+ eventType: EVENT_TYPE.OPERATIONAL
131
+ });
132
+ });
133
+ syncBlockAdded.forEach(function (syncBlock) {
134
+ if (fg('platform_synced_block_patch_3')) {
135
+ var _api$analytics2;
136
+ api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || (_api$analytics2 = _api$analytics2.actions) === null || _api$analytics2 === void 0 || _api$analytics2.fireAnalyticsEvent({
137
+ action: ACTION.INSERTED,
138
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
139
+ actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK,
140
+ attributes: {
141
+ resourceId: syncBlock.attrs.resourceId,
142
+ blockInstanceId: syncBlock.attrs.localId
143
+ },
144
+ eventType: EVENT_TYPE.TRACK
145
+ });
146
+ } else {
147
+ var _api$analytics3;
148
+ api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || (_api$analytics3 = _api$analytics3.actions) === null || _api$analytics3 === void 0 || _api$analytics3.fireAnalyticsEvent({
149
+ action: ACTION.INSERTED,
150
+ actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
151
+ actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_CREATE,
152
+ attributes: {
153
+ resourceId: syncBlock.attrs.resourceId,
154
+ blockInstanceId: syncBlock.attrs.localId
155
+ },
156
+ eventType: EVENT_TYPE.OPERATIONAL
157
+ });
158
+ }
159
+ });
160
+ if (bodiedSyncBlockRemoved.length > 0) {
161
+ // eslint-disable-next-line no-param-reassign
162
+ confirmationTransactionRef.current = tr;
163
+ return handleBodiedSyncBlockRemoval(bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef, getDeleteReason(tr));
164
+ }
165
+ if (bodiedSyncBlockAdded.length > 0) {
166
+ if (tr.getMeta(pmHistoryPluginKey)) {
167
+ // We don't allow bodiedSyncBlock creation via redo, however, we need to return true here to let transaction through so history can be updated properly.
168
+ // If we simply returns false, creation from redo is blocked as desired, but this results in editor showing redo as possible even though it's not.
169
+ // After true is returned here and the node is created, we delete the node in the filterTransaction immediately, which cancels out the creation
170
+ return true;
171
+ }
172
+ handleBodiedSyncBlockCreation(bodiedSyncBlockAdded, state, api);
173
+ return true;
174
+ }
175
+ showInlineExtensionInSyncBlockWarningIfNeeded(tr, state, api, inlineExtensionFlagShown);
176
+ return true;
177
+ };
178
+ var filterTransactionOffline = function filterTransactionOffline(_ref4) {
179
+ var tr = _ref4.tr,
180
+ state = _ref4.state,
181
+ api = _ref4.api,
182
+ isConfirmedSyncBlockDeletion = _ref4.isConfirmedSyncBlockDeletion,
183
+ bodiedSyncBlockRemoved = _ref4.bodiedSyncBlockRemoved,
184
+ bodiedSyncBlockAdded = _ref4.bodiedSyncBlockAdded;
185
+ var _trackSyncBlocks2 = trackSyncBlocks(function (node) {
186
+ return node.type.name === 'syncBlock';
187
+ }, tr, state),
188
+ syncBlockRemoved = _trackSyncBlocks2.removed,
189
+ syncBlockAdded = _trackSyncBlocks2.added;
190
+ var errorFlag = false;
191
+ if (isConfirmedSyncBlockDeletion || bodiedSyncBlockRemoved.length > 0 || syncBlockRemoved.length > 0) {
192
+ errorFlag = FLAG_ID.CANNOT_DELETE_WHEN_OFFLINE;
193
+ } else if (bodiedSyncBlockAdded.length > 0 || syncBlockAdded.length > 0) {
194
+ errorFlag = FLAG_ID.CANNOT_CREATE_WHEN_OFFLINE;
195
+ } else if (hasEditInSyncBlock(tr, state)) {
196
+ errorFlag = FLAG_ID.CANNOT_EDIT_WHEN_OFFLINE;
197
+ }
198
+ if (errorFlag) {
199
+ deferDispatch(function () {
200
+ api === null || api === void 0 || api.core.actions.execute(function (_ref5) {
201
+ var tr = _ref5.tr;
202
+ return tr.setMeta(syncedBlockPluginKey, {
203
+ activeFlag: {
204
+ id: errorFlag
205
+ }
206
+ });
207
+ });
208
+ });
209
+ return false;
210
+ }
211
+ return true;
212
+ };
213
+
214
+ /**
215
+ * Encapsulates mutable state that persists across transactions in the
216
+ * synced block plugin. Replaces module-level closure variables so state
217
+ * is explicitly scoped to a single plugin instance.
218
+ */
219
+ var SyncedBlockPluginContext = /*#__PURE__*/function () {
220
+ function SyncedBlockPluginContext() {
221
+ _classCallCheck(this, SyncedBlockPluginContext);
222
+ _defineProperty(this, "confirmationTransactionRef", {
223
+ current: undefined
224
+ });
225
+ _defineProperty(this, "_isCopyEvent", false);
226
+ _defineProperty(this, "unpublishedFlagShown", new Set());
227
+ _defineProperty(this, "inlineExtensionFlagShown", new Set());
228
+ }
229
+ return _createClass(SyncedBlockPluginContext, [{
230
+ key: "isCopyEvent",
231
+ get: function get() {
232
+ return this._isCopyEvent;
233
+ }
234
+ }, {
235
+ key: "markCopyEvent",
236
+ value: function markCopyEvent() {
237
+ this._isCopyEvent = true;
238
+ }
239
+ }, {
240
+ key: "consumeCopyEvent",
241
+ value: function consumeCopyEvent() {
242
+ var was = this._isCopyEvent;
243
+ this._isCopyEvent = false;
244
+ return was;
245
+ }
246
+ }]);
247
+ }();
106
248
  export var createPlugin = function createPlugin(options, pmPluginFactoryParams, syncBlockStore, api) {
107
- var _ref3 = options || {},
108
- _ref3$useLongPressSel = _ref3.useLongPressSelection,
109
- useLongPressSelection = _ref3$useLongPressSel === void 0 ? false : _ref3$useLongPressSel;
110
- var confirmationTransactionRef = {
249
+ var _ctx$confirmationTran, _ctx$unpublishedFlagS, _ctx$inlineExtensionF;
250
+ var _ref6 = options || {},
251
+ _ref6$useLongPressSel = _ref6.useLongPressSelection,
252
+ useLongPressSelection = _ref6$useLongPressSel === void 0 ? false : _ref6$useLongPressSel;
253
+ var ctx = fg('platform_synced_block_patch_5') ? new SyncedBlockPluginContext() : undefined;
254
+ var confirmationTransactionRef = (_ctx$confirmationTran = ctx === null || ctx === void 0 ? void 0 : ctx.confirmationTransactionRef) !== null && _ctx$confirmationTran !== void 0 ? _ctx$confirmationTran : {
111
255
  current: undefined
112
256
  };
113
- // Track if a copy event occurred to distinguish copy from drag and drop
114
257
  var isCopyEvent = false;
115
- // Track which sync blocks have already triggered the unpublished flag
116
- var unpublishedFlagShown = new Set();
117
- // Track which sync blocks have already triggered the inline extension in sync block flag
118
- var inlineExtensionFlagShown = new Set();
258
+ var unpublishedFlagShown = (_ctx$unpublishedFlagS = ctx === null || ctx === void 0 ? void 0 : ctx.unpublishedFlagShown) !== null && _ctx$unpublishedFlagS !== void 0 ? _ctx$unpublishedFlagS : new Set();
259
+ var inlineExtensionFlagShown = (_ctx$inlineExtensionF = ctx === null || ctx === void 0 ? void 0 : ctx.inlineExtensionFlagShown) !== null && _ctx$inlineExtensionF !== void 0 ? _ctx$inlineExtensionF : new Set();
119
260
 
120
261
  // Set up callback to detect unpublished sync blocks when they're fetched
121
262
  syncBlockStore.referenceManager.setOnUnpublishedSyncBlockDetected(function (resourceId) {
122
263
  // Only show the flag once per sync block
123
264
  if (!unpublishedFlagShown.has(resourceId)) {
124
265
  unpublishedFlagShown.add(resourceId);
125
- // Use setTimeout to dispatch transaction in next tick and avoid re-entrant dispatch
126
- setTimeout(function () {
127
- api === null || api === void 0 || api.core.actions.execute(function (_ref4) {
128
- var tr = _ref4.tr;
266
+ deferDispatch(function () {
267
+ api === null || api === void 0 || api.core.actions.execute(function (_ref7) {
268
+ var tr = _ref7.tr;
129
269
  return tr.setMeta(syncedBlockPluginKey, {
130
270
  activeFlag: {
131
271
  id: FLAG_ID.UNPUBLISHED_SYNC_BLOCK_PASTED
132
272
  }
133
273
  });
134
274
  });
135
- }, 0);
275
+ });
136
276
  }
137
277
  });
138
278
  return new SafePlugin({
@@ -175,20 +315,22 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
175
315
  props: {
176
316
  nodeViews: {
177
317
  syncBlock: function syncBlock(node, view, getPos, _decorations) {
178
- // To support SSR, pass `syncBlockStore` here
179
- // and do not use lazy loading.
180
- // We cannot start rendering and then load `syncBlockStore` asynchronously,
181
- // because obtaining it is asynchronous (sharedPluginState.currentState() is delayed).
182
- return new SyncBlockView({
183
- api: api,
184
- options: options,
185
- node: node,
186
- view: view,
187
- getPos: getPos,
188
- portalProviderAPI: pmPluginFactoryParams.portalProviderAPI,
189
- eventDispatcher: pmPluginFactoryParams.eventDispatcher,
190
- syncBlockStore: syncBlockStore
191
- }).init();
318
+ return (
319
+ // To support SSR, pass `syncBlockStore` here
320
+ // and do not use lazy loading.
321
+ // We cannot start rendering and then load `syncBlockStore` asynchronously,
322
+ // because obtaining it is asynchronous (sharedPluginState.currentState() is delayed).
323
+ new SyncBlockView({
324
+ api: api,
325
+ options: options,
326
+ node: node,
327
+ view: view,
328
+ getPos: getPos,
329
+ portalProviderAPI: pmPluginFactoryParams.portalProviderAPI,
330
+ eventDispatcher: pmPluginFactoryParams.eventDispatcher,
331
+ syncBlockStore: syncBlockStore
332
+ }).init()
333
+ );
192
334
  },
193
335
  bodiedSyncBlock: lazyBodiedSyncBlockView({
194
336
  pluginOptions: options,
@@ -239,17 +381,23 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
239
381
  return shouldIgnoreDomEvent(view, event, api);
240
382
  },
241
383
  copy: function copy() {
242
- isCopyEvent = true;
384
+ if (ctx) {
385
+ ctx.markCopyEvent();
386
+ } else {
387
+ isCopyEvent = true;
388
+ }
243
389
  return false;
244
390
  }
245
391
  },
246
- transformCopied: function transformCopied(slice, _ref5) {
247
- var state = _ref5.state;
392
+ transformCopied: function transformCopied(slice, _ref8) {
393
+ var state = _ref8.state;
248
394
  var pluginState = syncedBlockPluginKey.getState(state);
249
395
  var syncBlockStore = pluginState === null || pluginState === void 0 ? void 0 : pluginState.syncBlockStore;
250
396
  var schema = state.schema;
251
- var isCopy = isCopyEvent;
252
- isCopyEvent = false;
397
+ var isCopy = ctx ? ctx.consumeCopyEvent() : isCopyEvent;
398
+ if (!ctx) {
399
+ isCopyEvent = false;
400
+ }
253
401
  if (!syncBlockStore || !isCopy) {
254
402
  return slice;
255
403
  }
@@ -288,11 +436,10 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
288
436
 
289
437
  // Track newly added reference sync blocks before processing the transaction
290
438
  if (tr.docChanged && !tr.getMeta('isRemote')) {
291
- var _trackSyncBlocks = trackSyncBlocks(function (node) {
439
+ var _trackSyncBlocks3 = trackSyncBlocks(function (node) {
292
440
  return node.type.name === 'syncBlock';
293
441
  }, tr, state),
294
- added = _trackSyncBlocks.added;
295
- // Mark newly added sync blocks so we can detect unpublished status when data is fetched
442
+ added = _trackSyncBlocks3.added;
296
443
  added.forEach(function (nodeInfo) {
297
444
  var _nodeInfo$attrs;
298
445
  if ((_nodeInfo$attrs = nodeInfo.attrs) !== null && _nodeInfo$attrs !== void 0 && _nodeInfo$attrs.resourceId) {
@@ -300,26 +447,40 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
300
447
  }
301
448
  });
302
449
  }
303
-
304
- // Ignore transactions that don't change the document
305
- // or are from remote (collab) or already confirmed sync block deletion
306
- // We only care about local changes that change the document
307
- // and are not yet confirmed for sync block deletion
308
450
  if (!tr.docChanged || Boolean(tr.getMeta('isRemote')) || !isOffline && isConfirmedSyncBlockDeletion) {
309
451
  return true;
310
452
  }
311
- var _trackSyncBlocks2 = trackSyncBlocks(syncBlockStore.sourceManager.isSourceBlock, tr, state),
312
- bodiedSyncBlockRemoved = _trackSyncBlocks2.removed,
313
- bodiedSyncBlockAdded = _trackSyncBlocks2.added;
453
+ var _trackSyncBlocks4 = trackSyncBlocks(syncBlockStore.sourceManager.isSourceBlock, tr, state),
454
+ bodiedSyncBlockRemoved = _trackSyncBlocks4.removed,
455
+ bodiedSyncBlockAdded = _trackSyncBlocks4.added;
456
+ if (fg('platform_synced_block_patch_5')) {
457
+ return isOffline ? filterTransactionOffline({
458
+ tr: tr,
459
+ state: state,
460
+ api: api,
461
+ isConfirmedSyncBlockDeletion: isConfirmedSyncBlockDeletion,
462
+ bodiedSyncBlockRemoved: bodiedSyncBlockRemoved,
463
+ bodiedSyncBlockAdded: bodiedSyncBlockAdded
464
+ }) : filterTransactionOnline({
465
+ tr: tr,
466
+ state: state,
467
+ syncBlockStore: syncBlockStore,
468
+ api: api,
469
+ confirmationTransactionRef: confirmationTransactionRef,
470
+ bodiedSyncBlockRemoved: bodiedSyncBlockRemoved,
471
+ bodiedSyncBlockAdded: bodiedSyncBlockAdded,
472
+ inlineExtensionFlagShown: inlineExtensionFlagShown
473
+ });
474
+ }
314
475
  if (!isOffline) {
315
- var _trackSyncBlocks3 = trackSyncBlocks(function (node) {
476
+ var _trackSyncBlocks5 = trackSyncBlocks(function (node) {
316
477
  return node.type.name === 'syncBlock';
317
478
  }, tr, state),
318
- syncBlockRemoved = _trackSyncBlocks3.removed,
319
- syncBlockAdded = _trackSyncBlocks3.added;
320
- syncBlockRemoved.forEach(function (syncBlock) {
321
- var _api$analytics;
322
- api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 || _api$analytics.fireAnalyticsEvent({
479
+ _syncBlockRemoved = _trackSyncBlocks5.removed,
480
+ _syncBlockAdded = _trackSyncBlocks5.added;
481
+ _syncBlockRemoved.forEach(function (syncBlock) {
482
+ var _api$analytics4;
483
+ api === null || api === void 0 || (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 || (_api$analytics4 = _api$analytics4.actions) === null || _api$analytics4 === void 0 || _api$analytics4.fireAnalyticsEvent({
323
484
  action: ACTION.DELETED,
324
485
  actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
325
486
  actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_DELETE,
@@ -330,10 +491,10 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
330
491
  eventType: EVENT_TYPE.OPERATIONAL
331
492
  });
332
493
  });
333
- syncBlockAdded.forEach(function (syncBlock) {
494
+ _syncBlockAdded.forEach(function (syncBlock) {
334
495
  if (fg('platform_synced_block_patch_3')) {
335
- var _api$analytics2;
336
- api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || (_api$analytics2 = _api$analytics2.actions) === null || _api$analytics2 === void 0 || _api$analytics2.fireAnalyticsEvent({
496
+ var _api$analytics5;
497
+ api === null || api === void 0 || (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 || (_api$analytics5 = _api$analytics5.actions) === null || _api$analytics5 === void 0 || _api$analytics5.fireAnalyticsEvent({
337
498
  action: ACTION.INSERTED,
338
499
  actionSubject: ACTION_SUBJECT.DOCUMENT,
339
500
  actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK,
@@ -344,8 +505,8 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
344
505
  eventType: EVENT_TYPE.TRACK
345
506
  });
346
507
  } else {
347
- var _api$analytics3;
348
- api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || (_api$analytics3 = _api$analytics3.actions) === null || _api$analytics3 === void 0 || _api$analytics3.fireAnalyticsEvent({
508
+ var _api$analytics6;
509
+ api === null || api === void 0 || (_api$analytics6 = api.analytics) === null || _api$analytics6 === void 0 || (_api$analytics6 = _api$analytics6.actions) === null || _api$analytics6 === void 0 || _api$analytics6.fireAnalyticsEvent({
349
510
  action: ACTION.INSERTED,
350
511
  actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
351
512
  actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_CREATE,
@@ -362,7 +523,7 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
362
523
  return handleBodiedSyncBlockRemoval(bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef, getDeleteReason(tr));
363
524
  }
364
525
  if (bodiedSyncBlockAdded.length > 0) {
365
- if (Boolean(tr.getMeta(pmHistoryPluginKey))) {
526
+ if (tr.getMeta(pmHistoryPluginKey)) {
366
527
  // We don't allow bodiedSyncBlock creation via redo, however, we need to return true here to let transaction through so history can be updated properly.
367
528
  // If we simply returns false, creation from redo is blocked as desired, but this results in editor showing redo as possible even though it's not.
368
529
  // After true is returned here and the node is created, we delete the node in the filterTransaction immediately, which cancels out the creation
@@ -373,36 +534,34 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
373
534
  }
374
535
  showInlineExtensionInSyncBlockWarningIfNeeded(tr, state, api, inlineExtensionFlagShown);
375
536
  return true;
376
- } else {
377
- var _trackSyncBlocks4 = trackSyncBlocks(function (node) {
378
- return node.type.name === 'syncBlock';
379
- }, tr, state),
380
- _syncBlockRemoved = _trackSyncBlocks4.removed,
381
- _syncBlockAdded = _trackSyncBlocks4.added;
382
- var errorFlag = false;
537
+ }
538
+ var _trackSyncBlocks6 = trackSyncBlocks(function (node) {
539
+ return node.type.name === 'syncBlock';
540
+ }, tr, state),
541
+ syncBlockRemoved = _trackSyncBlocks6.removed,
542
+ syncBlockAdded = _trackSyncBlocks6.added;
543
+ var errorFlag = false;
383
544
 
384
- // Disable (bodied)syncBlock node deletion/creation/edition in offline mode and trigger an error flag instead
385
- if (isConfirmedSyncBlockDeletion || bodiedSyncBlockRemoved.length > 0 || _syncBlockRemoved.length > 0) {
386
- errorFlag = FLAG_ID.CANNOT_DELETE_WHEN_OFFLINE;
387
- } else if (bodiedSyncBlockAdded.length > 0 || _syncBlockAdded.length > 0) {
388
- errorFlag = FLAG_ID.CANNOT_CREATE_WHEN_OFFLINE;
389
- } else if (hasEditInSyncBlock(tr, state)) {
390
- errorFlag = FLAG_ID.CANNOT_EDIT_WHEN_OFFLINE;
391
- }
392
- if (errorFlag) {
393
- // Use setTimeout to dispatch transaction in next tick and avoid re-entrant dispatch
394
- setTimeout(function () {
395
- api === null || api === void 0 || api.core.actions.execute(function (_ref6) {
396
- var tr = _ref6.tr;
397
- return tr.setMeta(syncedBlockPluginKey, {
398
- activeFlag: {
399
- id: errorFlag
400
- }
401
- });
545
+ // Disable (bodied)syncBlock node deletion/creation/edition in offline mode and trigger an error flag instead
546
+ if (isConfirmedSyncBlockDeletion || bodiedSyncBlockRemoved.length > 0 || syncBlockRemoved.length > 0) {
547
+ errorFlag = FLAG_ID.CANNOT_DELETE_WHEN_OFFLINE;
548
+ } else if (bodiedSyncBlockAdded.length > 0 || syncBlockAdded.length > 0) {
549
+ errorFlag = FLAG_ID.CANNOT_CREATE_WHEN_OFFLINE;
550
+ } else if (hasEditInSyncBlock(tr, state)) {
551
+ errorFlag = FLAG_ID.CANNOT_EDIT_WHEN_OFFLINE;
552
+ }
553
+ if (errorFlag) {
554
+ deferDispatch(function () {
555
+ api === null || api === void 0 || api.core.actions.execute(function (_ref9) {
556
+ var tr = _ref9.tr;
557
+ return tr.setMeta(syncedBlockPluginKey, {
558
+ activeFlag: {
559
+ id: errorFlag
560
+ }
402
561
  });
403
- }, 0);
404
- return false;
405
- }
562
+ });
563
+ });
564
+ return false;
406
565
  }
407
566
  return true;
408
567
  },
@@ -419,29 +578,27 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
419
578
  try {
420
579
  var _loop = function _loop() {
421
580
  var tr = _step2.value;
422
- if (!tr.getMeta(pmHistoryPluginKey)) {
423
- return 0; // continue
424
- }
425
- var _trackSyncBlocks5 = trackSyncBlocks(syncBlockStore.sourceManager.isSourceBlock, tr, oldState),
426
- added = _trackSyncBlocks5.added;
427
- if (added.length > 0) {
428
- // Delete bodiedSyncBlock if it's originated from history, i.e. redo creation
429
- // See filterTransaction above for more details
430
- var _tr = newState.tr;
431
- added.forEach(function (node) {
432
- if (node.from !== undefined && node.to !== undefined) {
433
- _tr.delete(node.from, node.to);
434
- }
435
- });
436
- return {
437
- v: _tr
438
- };
581
+ if (tr.getMeta(pmHistoryPluginKey)) {
582
+ var _trackSyncBlocks7 = trackSyncBlocks(syncBlockStore.sourceManager.isSourceBlock, tr, oldState),
583
+ added = _trackSyncBlocks7.added;
584
+ if (added.length > 0) {
585
+ // Delete bodiedSyncBlock if it's originated from history, i.e. redo creation
586
+ // See filterTransaction above for more details
587
+ var _tr = newState.tr;
588
+ added.forEach(function (node) {
589
+ if (node.from !== undefined && node.to !== undefined) {
590
+ _tr.delete(node.from, node.to);
591
+ }
592
+ });
593
+ return {
594
+ v: _tr
595
+ };
596
+ }
439
597
  }
440
598
  },
441
599
  _ret;
442
600
  for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
443
601
  _ret = _loop();
444
- if (_ret === 0) continue;
445
602
  if (_ret) return _ret.v;
446
603
  }
447
604
  } catch (err) {
@@ -4,6 +4,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
4
4
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
5
5
  import { FLAG_ID } from '../../types';
6
6
  import { syncedBlockPluginKey } from '../main';
7
+ import { deferDispatch } from './utils';
7
8
  var onRetry = function onRetry(api, resourceId) {
8
9
  return function () {
9
10
  var _api$core, _api$core2;
@@ -79,7 +80,7 @@ export var handleBodiedSyncBlockCreation = function handleBodiedSyncBlockCreatio
79
80
  to: node.to
80
81
  };
81
82
  var resourceId = node.attrs.resourceId;
82
- setTimeout(function () {
83
+ deferDispatch(function () {
83
84
  var _api$core3;
84
85
  api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref2) {
85
86
  var tr = _ref2.tr;
@@ -2,6 +2,19 @@ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
2
2
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
3
3
  import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
4
4
  import { findParentNodeOfType, findParentNodeOfTypeClosestToPos, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
5
+ import { fg } from '@atlaskit/platform-feature-flags';
6
+
7
+ /**
8
+ * Defers a callback to the next microtask (when gated) or next macrotask via setTimeout(0).
9
+ * Used to avoid re-entrant ProseMirror dispatch cycles.
10
+ */
11
+ export var deferDispatch = function deferDispatch(fn) {
12
+ if (fg('platform_synced_block_patch_5')) {
13
+ queueMicrotask(fn);
14
+ } else {
15
+ setTimeout(fn, 0);
16
+ }
17
+ };
5
18
  export var findSyncBlock = function findSyncBlock(schema, selection) {
6
19
  var syncBlock = schema.nodes.syncBlock;
7
20
  return findSelectedNodeOfType(syncBlock)(selection);
@@ -2,6 +2,11 @@ import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
2
  import type { NodeType, Node as PMNode, Schema, Slice } from '@atlaskit/editor-prosemirror/model';
3
3
  import type { EditorState, Selection, Transaction } from '@atlaskit/editor-prosemirror/state';
4
4
  import type { ContentNodeWithPos } from '@atlaskit/editor-prosemirror/utils';
5
+ /**
6
+ * Defers a callback to the next microtask (when gated) or next macrotask via setTimeout(0).
7
+ * Used to avoid re-entrant ProseMirror dispatch cycles.
8
+ */
9
+ export declare const deferDispatch: (fn: () => void) => void;
5
10
  export declare const findSyncBlock: (schema: Schema, selection: Selection) => ContentNodeWithPos | undefined;
6
11
  export declare const findBodiedSyncBlock: (schema: Schema, selection: Selection) => ContentNodeWithPos | undefined;
7
12
  export declare const findSyncBlockOrBodiedSyncBlock: (schema: Schema, selection: Selection) => ContentNodeWithPos | undefined;
@@ -2,6 +2,11 @@ import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
2
  import type { NodeType, Node as PMNode, Schema, Slice } from '@atlaskit/editor-prosemirror/model';
3
3
  import type { EditorState, Selection, Transaction } from '@atlaskit/editor-prosemirror/state';
4
4
  import type { ContentNodeWithPos } from '@atlaskit/editor-prosemirror/utils';
5
+ /**
6
+ * Defers a callback to the next microtask (when gated) or next macrotask via setTimeout(0).
7
+ * Used to avoid re-entrant ProseMirror dispatch cycles.
8
+ */
9
+ export declare const deferDispatch: (fn: () => void) => void;
5
10
  export declare const findSyncBlock: (schema: Schema, selection: Selection) => ContentNodeWithPos | undefined;
6
11
  export declare const findBodiedSyncBlock: (schema: Schema, selection: Selection) => ContentNodeWithPos | undefined;
7
12
  export declare const findSyncBlockOrBodiedSyncBlock: (schema: Schema, selection: Selection) => ContentNodeWithPos | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-synced-block",
3
- "version": "5.3.32",
3
+ "version": "5.3.34",
4
4
  "description": "SyncedBlock plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -30,7 +30,7 @@
30
30
  "dependencies": {
31
31
  "@atlaskit/adf-schema": "^52.0.0",
32
32
  "@atlaskit/button": "23.9.9",
33
- "@atlaskit/dropdown-menu": "16.4.7",
33
+ "@atlaskit/dropdown-menu": "16.5.0",
34
34
  "@atlaskit/editor-json-transformer": "^8.31.0",
35
35
  "@atlaskit/editor-plugin-analytics": "^7.0.0",
36
36
  "@atlaskit/editor-plugin-block-menu": "^6.1.0",
@@ -107,6 +107,9 @@
107
107
  "platform_synced_block_patch_3": {
108
108
  "type": "boolean"
109
109
  },
110
+ "platform_synced_block_patch_5": {
111
+ "type": "boolean"
112
+ },
110
113
  "platform_editor_block_menu_v2_patch_3": {
111
114
  "type": "boolean"
112
115
  }