@atlaskit/editor-plugin-synced-block 10.4.7 → 10.5.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 +11 -0
- package/dist/cjs/editor-commands/index.js +6 -1
- package/dist/cjs/pm-plugins/main.js +215 -25
- package/dist/cjs/pm-plugins/utils/handle-bodied-sync-block-removal.js +5 -1
- package/dist/cjs/ui/floating-toolbar.js +3 -2
- package/dist/es2019/editor-commands/index.js +6 -1
- package/dist/es2019/pm-plugins/main.js +178 -11
- package/dist/es2019/pm-plugins/utils/handle-bodied-sync-block-removal.js +5 -1
- package/dist/es2019/ui/floating-toolbar.js +3 -2
- package/dist/esm/editor-commands/index.js +6 -1
- package/dist/esm/pm-plugins/main.js +214 -24
- package/dist/esm/pm-plugins/utils/handle-bodied-sync-block-removal.js +5 -1
- package/dist/esm/ui/floating-toolbar.js +3 -2
- package/dist/types/pm-plugins/main.d.ts +2 -1
- package/dist/types/pm-plugins/utils/handle-bodied-sync-block-removal.d.ts +7 -1
- package/dist/types/syncedBlockPluginType.d.ts +2 -2
- package/package.json +3 -3
|
@@ -13,6 +13,7 @@ import { convertPMNodesToSyncBlockNodes, rebaseTransaction } from '@atlaskit/edi
|
|
|
13
13
|
import { getSourceProductFromResourceIdSafe } from '@atlaskit/editor-synced-block-provider/utils';
|
|
14
14
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
15
15
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
16
|
+
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
|
|
16
17
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
17
18
|
import { bodiedSyncBlockNodeView, bodiedSyncBlockNodeViewOld } from '../nodeviews/bodiedSyncedBlock';
|
|
18
19
|
import { SyncBlock as SyncBlockView } from '../nodeviews/syncedBlock';
|
|
@@ -37,6 +38,7 @@ export const syncedBlockPluginKey = new PluginKey('syncedBlockPlugin');
|
|
|
37
38
|
* `platform_editor_blocks_patch_4`.
|
|
38
39
|
*/
|
|
39
40
|
export const deleteMechanismMetaKey = new PluginKey('syncedBlockDeleteMechanism');
|
|
41
|
+
const syncedBlockPromptedFeedbackMetaKey = new PluginKey('syncedBlockPromptedFeedback');
|
|
40
42
|
|
|
41
43
|
/**
|
|
42
44
|
* Creation-type signals set by {@link createSyncedBlock} on the creating
|
|
@@ -121,7 +123,7 @@ const getDeleteReason = tr => {
|
|
|
121
123
|
};
|
|
122
124
|
|
|
123
125
|
/** Narrows the history plugin meta, matching the editor-plugin-card pattern. */
|
|
124
|
-
const isHistoryMeta = meta => typeof meta === 'object' && meta !== null && 'redo' in meta;
|
|
126
|
+
const isHistoryMeta = meta => typeof meta === 'object' && meta !== null && 'redo' in meta && typeof meta.redo === 'boolean';
|
|
125
127
|
|
|
126
128
|
/**
|
|
127
129
|
* Derive how a source bodiedSyncBlock removal was performed, for the `mechanism`
|
|
@@ -145,9 +147,16 @@ const isHistoryMeta = meta => typeof meta === 'object' && meta !== null && 'redo
|
|
|
145
147
|
* selected when the edit was made.
|
|
146
148
|
*/
|
|
147
149
|
export const getDeleteMechanism = (tr, state) => {
|
|
148
|
-
var _selection$node;
|
|
150
|
+
var _selection$node, _selection$node2;
|
|
151
|
+
// Keep the legacy analytics classification unchanged while activation is off.
|
|
152
|
+
// The stricter history, structural-step, and reference-selection handling is
|
|
153
|
+
// only needed by the prompted feedback rollout.
|
|
154
|
+
const isSyncBlockActivationEnabled = expValEqualsNoExposure('platform_editor_sync_block_activation', 'isEnabled', true);
|
|
149
155
|
const historyMeta = tr.getMeta(pmHistoryPluginKey);
|
|
150
156
|
if (historyMeta) {
|
|
157
|
+
if (isSyncBlockActivationEnabled && !isHistoryMeta(historyMeta)) {
|
|
158
|
+
return 'other';
|
|
159
|
+
}
|
|
151
160
|
return isHistoryMeta(historyMeta) && historyMeta.redo ? 'redo' : 'undo';
|
|
152
161
|
}
|
|
153
162
|
|
|
@@ -156,16 +165,26 @@ export const getDeleteMechanism = (tr, state) => {
|
|
|
156
165
|
if (tr.getMeta(deleteMechanismMetaKey) === 'deleteButton') {
|
|
157
166
|
return 'deleteButton';
|
|
158
167
|
}
|
|
168
|
+
const hasStructuralStep = isSyncBlockActivationEnabled && tr.steps.some(step => step instanceof ReplaceAroundStep);
|
|
159
169
|
const hasReplaceStep = tr.steps.some(step => step instanceof ReplaceStep);
|
|
160
|
-
if (!hasReplaceStep) {
|
|
170
|
+
if (hasStructuralStep || !hasReplaceStep) {
|
|
161
171
|
return 'other';
|
|
162
172
|
}
|
|
163
173
|
const {
|
|
164
174
|
selection
|
|
165
175
|
} = state;
|
|
166
|
-
const isNodeSelected = selection instanceof NodeSelection && ((_selection$node = selection.node) === null || _selection$node === void 0 ? void 0 : _selection$node.type.name) === 'bodiedSyncBlock';
|
|
176
|
+
const isNodeSelected = selection instanceof NodeSelection && (((_selection$node = selection.node) === null || _selection$node === void 0 ? void 0 : _selection$node.type.name) === 'bodiedSyncBlock' || isSyncBlockActivationEnabled && ((_selection$node2 = selection.node) === null || _selection$node2 === void 0 ? void 0 : _selection$node2.type.name) === 'syncBlock');
|
|
167
177
|
return isNodeSelected ? 'selectionReplaced' : 'keyboardDelete';
|
|
168
178
|
};
|
|
179
|
+
export const getPromptedFeedbackEntryPoint = mechanism => {
|
|
180
|
+
if (mechanism === 'undo') {
|
|
181
|
+
return 'prompted-undo';
|
|
182
|
+
}
|
|
183
|
+
if (mechanism === 'deleteButton' || mechanism === 'keyboardDelete' || mechanism === 'selectionReplaced') {
|
|
184
|
+
return 'prompted-delete';
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
};
|
|
169
188
|
/**
|
|
170
189
|
* True when a source `bodiedSyncBlock` holds user content — i.e. not just the
|
|
171
190
|
* single empty paragraph it is created with (used to detect empty→content).
|
|
@@ -211,6 +230,7 @@ const filterTransactionOnline = ({
|
|
|
211
230
|
syncBlockStore,
|
|
212
231
|
api,
|
|
213
232
|
confirmationTransactionRef,
|
|
233
|
+
ctx,
|
|
214
234
|
bodiedSyncBlockRemoved,
|
|
215
235
|
bodiedSyncBlockAdded,
|
|
216
236
|
extensionFlagShown
|
|
@@ -241,6 +261,19 @@ const filterTransactionOnline = ({
|
|
|
241
261
|
// dedicated `cross_product_paste` event subject.
|
|
242
262
|
const isPaste = Boolean((_tr$getMeta = tr.getMeta('paste')) !== null && _tr$getMeta !== void 0 ? _tr$getMeta : tr.getMeta('uiEvent') === 'paste');
|
|
243
263
|
const isPasteOrDrop = isPaste || tr.getMeta('uiEvent') === 'drop';
|
|
264
|
+
const hasRemovedSyncBlock = syncBlockRemoved.length > 0 || bodiedSyncBlockRemoved.length > 0;
|
|
265
|
+
const isCutRemoval = hasRemovedSyncBlock && ctx.consumeCutRemoval();
|
|
266
|
+
const canPromptForRemoval = Boolean(ctx.onGiveFeedback) && hasRemovedSyncBlock && !isDirtyTransaction(tr) && !isCutRemoval && !isPasteOrDrop;
|
|
267
|
+
const promptedFeedbackEntryPoint = canPromptForRemoval ? getPromptedFeedbackEntryPoint(getDeleteMechanism(tr, state)) : undefined;
|
|
268
|
+
const entryPoint = promptedFeedbackEntryPoint && expValEqualsNoExposure('platform_editor_sync_block_activation', 'isEnabled', true) ? promptedFeedbackEntryPoint : undefined;
|
|
269
|
+
if (entryPoint && syncBlockRemoved.length > 0 && bodiedSyncBlockRemoved.length === 0) {
|
|
270
|
+
tr.setMeta(syncedBlockPromptedFeedbackMetaKey, {
|
|
271
|
+
context: {
|
|
272
|
+
blockType: 'reference',
|
|
273
|
+
entryPoint
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
244
277
|
syncBlockAdded.forEach(syncBlock => {
|
|
245
278
|
var _api$analytics2, _api$analytics2$actio;
|
|
246
279
|
api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : (_api$analytics2$actio = _api$analytics2.actions) === null || _api$analytics2$actio === void 0 ? void 0 : _api$analytics2$actio.fireAnalyticsEvent({
|
|
@@ -268,7 +301,22 @@ const filterTransactionOnline = ({
|
|
|
268
301
|
}
|
|
269
302
|
// Only derive the mechanism behind the gate — discarded gate-off.
|
|
270
303
|
const mechanism = fg('platform_editor_blocks_patch_4') ? getDeleteMechanism(tr, state) : undefined;
|
|
271
|
-
|
|
304
|
+
const feedbackContext = entryPoint && getDeleteReason(tr) !== 'source-block-unsynced' ? {
|
|
305
|
+
blockType: 'source',
|
|
306
|
+
entryPoint
|
|
307
|
+
} : undefined;
|
|
308
|
+
if (feedbackContext) {
|
|
309
|
+
const sourceAttempt = ctx.queueSourceFeedback(feedbackContext);
|
|
310
|
+
return handleBodiedSyncBlockRemoval(bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef, getDeleteReason(tr), mechanism, {
|
|
311
|
+
onDeleteCompleted: success => ctx.completeSourceDeletion(sourceAttempt, success),
|
|
312
|
+
onDeleteTransaction: deleteTr => deleteTr.setMeta(syncedBlockPromptedFeedbackMetaKey, {
|
|
313
|
+
context: feedbackContext,
|
|
314
|
+
sourceAttempt
|
|
315
|
+
}),
|
|
316
|
+
onDestroy: () => ctx.clearSourceFeedback(sourceAttempt)
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
return handleBodiedSyncBlockRemoval(bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef, getDeleteReason(tr), mechanism, undefined);
|
|
272
320
|
}
|
|
273
321
|
if (bodiedSyncBlockAdded.length > 0) {
|
|
274
322
|
if (tr.getMeta(pmHistoryPluginKey)) {
|
|
@@ -391,14 +439,17 @@ const buildStatusDecorations = (doc, syncBlockStore, isOffline, isViewMode, isDr
|
|
|
391
439
|
* is explicitly scoped to a single plugin instance.
|
|
392
440
|
*/
|
|
393
441
|
class SyncedBlockPluginContext {
|
|
394
|
-
constructor() {
|
|
442
|
+
constructor(onGiveFeedback) {
|
|
395
443
|
_defineProperty(this, "confirmationTransactionRef", {
|
|
396
444
|
current: undefined
|
|
397
445
|
});
|
|
446
|
+
_defineProperty(this, "_cutRemovalPending", false);
|
|
447
|
+
_defineProperty(this, "cutRemovalGeneration", 0);
|
|
398
448
|
_defineProperty(this, "_isCopyEvent", false);
|
|
399
449
|
_defineProperty(this, "_isCutEvent", false);
|
|
400
450
|
_defineProperty(this, "unpublishedFlagShown", new Set());
|
|
401
451
|
_defineProperty(this, "extensionFlagShown", new Set());
|
|
452
|
+
this.onGiveFeedback = onGiveFeedback;
|
|
402
453
|
}
|
|
403
454
|
get isCopyEvent() {
|
|
404
455
|
return this._isCopyEvent;
|
|
@@ -419,6 +470,86 @@ class SyncedBlockPluginContext {
|
|
|
419
470
|
this._isCutEvent = false;
|
|
420
471
|
return was;
|
|
421
472
|
}
|
|
473
|
+
markCutRemovalPending() {
|
|
474
|
+
this._cutRemovalPending = true;
|
|
475
|
+
const generation = ++this.cutRemovalGeneration;
|
|
476
|
+
queueMicrotask(() => {
|
|
477
|
+
if (this.cutRemovalGeneration === generation) {
|
|
478
|
+
this._cutRemovalPending = false;
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
consumeCutRemoval() {
|
|
483
|
+
const wasPending = this._cutRemovalPending;
|
|
484
|
+
this._cutRemovalPending = false;
|
|
485
|
+
this.cutRemovalGeneration += 1;
|
|
486
|
+
return wasPending;
|
|
487
|
+
}
|
|
488
|
+
queueSourceFeedback(context) {
|
|
489
|
+
const sourceAttempt = Symbol('syncedBlockSourceFeedbackAttempt');
|
|
490
|
+
this.pendingSourceFeedback = {
|
|
491
|
+
context,
|
|
492
|
+
deletionSucceeded: false,
|
|
493
|
+
sourceAttempt,
|
|
494
|
+
transactionApplied: false
|
|
495
|
+
};
|
|
496
|
+
return sourceAttempt;
|
|
497
|
+
}
|
|
498
|
+
completeSourceDeletion(sourceAttempt, success) {
|
|
499
|
+
var _this$pendingSourceFe;
|
|
500
|
+
if (((_this$pendingSourceFe = this.pendingSourceFeedback) === null || _this$pendingSourceFe === void 0 ? void 0 : _this$pendingSourceFe.sourceAttempt) !== sourceAttempt) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
if (!success) {
|
|
504
|
+
// Keep the attempt pending because retryDeletion reuses these callbacks.
|
|
505
|
+
// Dismissal or cancellation clears it through the destroy callback.
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
this.pendingSourceFeedback.deletionSucceeded = true;
|
|
509
|
+
this.flushSourceFeedback(sourceAttempt);
|
|
510
|
+
}
|
|
511
|
+
clearSourceFeedback(sourceAttempt) {
|
|
512
|
+
var _this$pendingSourceFe2;
|
|
513
|
+
if (((_this$pendingSourceFe2 = this.pendingSourceFeedback) === null || _this$pendingSourceFe2 === void 0 ? void 0 : _this$pendingSourceFe2.sourceAttempt) === sourceAttempt) {
|
|
514
|
+
this.pendingSourceFeedback = undefined;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
handleAppliedFeedback({
|
|
518
|
+
context,
|
|
519
|
+
sourceAttempt
|
|
520
|
+
}) {
|
|
521
|
+
var _this$pendingSourceFe3;
|
|
522
|
+
if (context.blockType === 'source' && sourceAttempt && ((_this$pendingSourceFe3 = this.pendingSourceFeedback) === null || _this$pendingSourceFe3 === void 0 ? void 0 : _this$pendingSourceFe3.sourceAttempt) === sourceAttempt) {
|
|
523
|
+
this.pendingSourceFeedback.transactionApplied = true;
|
|
524
|
+
this.flushSourceFeedback(sourceAttempt);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
if (context.blockType === 'reference') {
|
|
528
|
+
this.invokeFeedback(context);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
flushSourceFeedback(sourceAttempt) {
|
|
532
|
+
var _this$pendingSourceFe4, _this$pendingSourceFe5;
|
|
533
|
+
if (((_this$pendingSourceFe4 = this.pendingSourceFeedback) === null || _this$pendingSourceFe4 === void 0 ? void 0 : _this$pendingSourceFe4.sourceAttempt) === sourceAttempt && (_this$pendingSourceFe5 = this.pendingSourceFeedback) !== null && _this$pendingSourceFe5 !== void 0 && _this$pendingSourceFe5.deletionSucceeded && this.pendingSourceFeedback.transactionApplied) {
|
|
534
|
+
const {
|
|
535
|
+
context
|
|
536
|
+
} = this.pendingSourceFeedback;
|
|
537
|
+
this.pendingSourceFeedback = undefined;
|
|
538
|
+
this.invokeFeedback(context);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
invokeFeedback(context) {
|
|
542
|
+
deferDispatch(() => {
|
|
543
|
+
try {
|
|
544
|
+
var _this$onGiveFeedback;
|
|
545
|
+
const feedbackResult = (_this$onGiveFeedback = this.onGiveFeedback) === null || _this$onGiveFeedback === void 0 ? void 0 : _this$onGiveFeedback.call(this, context);
|
|
546
|
+
void Promise.resolve(feedbackResult).catch(() => {});
|
|
547
|
+
} catch {
|
|
548
|
+
// Product feedback collectors are optional UI. Their failures must
|
|
549
|
+
// never affect the already-applied editor transaction.
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
}
|
|
422
553
|
}
|
|
423
554
|
export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api) => {
|
|
424
555
|
const {
|
|
@@ -430,7 +561,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
430
561
|
// and avoids ~10 redundant Statsig SDK evaluations per keystroke in hot paths
|
|
431
562
|
// (apply, filterTransaction, appendTransaction, decorations).
|
|
432
563
|
const isPerfExperimentOn = expValEquals('editor_synced_block_perf', 'isEnabled', true);
|
|
433
|
-
const ctx = new SyncedBlockPluginContext();
|
|
564
|
+
const ctx = new SyncedBlockPluginContext(options === null || options === void 0 ? void 0 : options.onGiveFeedback);
|
|
434
565
|
const confirmationTransactionRef = ctx.confirmationTransactionRef;
|
|
435
566
|
const unpublishedFlagShown = ctx.unpublishedFlagShown;
|
|
436
567
|
const extensionFlagShown = ctx.extensionFlagShown;
|
|
@@ -781,7 +912,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
781
912
|
return false;
|
|
782
913
|
},
|
|
783
914
|
cut: () => {
|
|
784
|
-
if (fg('platform_synced_block_patch_13')) {
|
|
915
|
+
if (fg('platform_synced_block_patch_13') || Boolean(options === null || options === void 0 ? void 0 : options.onGiveFeedback) && expValEqualsNoExposure('platform_editor_sync_block_activation', 'isEnabled', true)) {
|
|
785
916
|
ctx.consumeCutEvent();
|
|
786
917
|
ctx.markCutEvent();
|
|
787
918
|
}
|
|
@@ -822,20 +953,40 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
822
953
|
} = state;
|
|
823
954
|
const isCopy = ctx.consumeCopyEvent();
|
|
824
955
|
const isSyncedBlockPatch13Enabled = fg('platform_synced_block_patch_13');
|
|
825
|
-
const
|
|
826
|
-
|
|
956
|
+
const wasCut = ctx.consumeCutEvent();
|
|
957
|
+
const isCut = isSyncedBlockPatch13Enabled && wasCut;
|
|
958
|
+
const isPromptedFeedbackCut = Boolean(syncBlockStore && (options === null || options === void 0 ? void 0 : options.onGiveFeedback) && wasCut) && expValEqualsNoExposure('platform_editor_sync_block_activation', 'isEnabled', true);
|
|
959
|
+
if (!syncBlockStore || !isCopy && !isCut && !isPromptedFeedbackCut) {
|
|
827
960
|
return slice;
|
|
828
961
|
}
|
|
829
|
-
|
|
962
|
+
if (isPromptedFeedbackCut && !isCut) {
|
|
963
|
+
let containsCutSyncBlock = false;
|
|
964
|
+
mapSlice(slice, node => {
|
|
965
|
+
if (syncBlockStore.referenceManager.isReferenceBlock(node) || node.type.name === 'bodiedSyncBlock' && sliceFullyContainsNode(slice, node)) {
|
|
966
|
+
containsCutSyncBlock = true;
|
|
967
|
+
}
|
|
968
|
+
return node;
|
|
969
|
+
});
|
|
970
|
+
if (containsCutSyncBlock) {
|
|
971
|
+
ctx.markCutRemovalPending();
|
|
972
|
+
}
|
|
973
|
+
return slice;
|
|
974
|
+
}
|
|
975
|
+
let containsCutSyncBlock = false;
|
|
976
|
+
const transformedSlice = mapSlice(slice, node => {
|
|
830
977
|
if (syncBlockStore.referenceManager.isReferenceBlock(node)) {
|
|
831
978
|
var _syncBlockStore$refer, _syncBlockStore$refer2;
|
|
832
979
|
if (isCut) {
|
|
980
|
+
containsCutSyncBlock = isPromptedFeedbackCut;
|
|
833
981
|
return node;
|
|
834
982
|
}
|
|
835
983
|
showCopiedFlag(api, options === null || options === void 0 ? void 0 : options.__livePage, ((_syncBlockStore$refer = syncBlockStore.referenceManager.getFromCache(node.attrs.resourceId)) === null || _syncBlockStore$refer === void 0 ? void 0 : (_syncBlockStore$refer2 = _syncBlockStore$refer.data) === null || _syncBlockStore$refer2 === void 0 ? void 0 : _syncBlockStore$refer2.status) === 'unpublished', getSourceProductFromResourceIdSafe(node.attrs.resourceId));
|
|
836
984
|
return node;
|
|
837
985
|
}
|
|
838
986
|
if (node.type.name === 'bodiedSyncBlock' && node.attrs.resourceId) {
|
|
987
|
+
if (isPromptedFeedbackCut && isCut && sliceFullyContainsNode(slice, node)) {
|
|
988
|
+
containsCutSyncBlock = true;
|
|
989
|
+
}
|
|
839
990
|
// if we only selected part of the bodied sync block content,
|
|
840
991
|
// remove the sync block node and only keep the content
|
|
841
992
|
if (!sliceFullyContainsNode(slice, node)) {
|
|
@@ -860,6 +1011,10 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
860
1011
|
}
|
|
861
1012
|
return node;
|
|
862
1013
|
});
|
|
1014
|
+
if (containsCutSyncBlock) {
|
|
1015
|
+
ctx.markCutRemovalPending();
|
|
1016
|
+
}
|
|
1017
|
+
return transformedSlice;
|
|
863
1018
|
}
|
|
864
1019
|
},
|
|
865
1020
|
filterTransaction: (tr, state) => {
|
|
@@ -939,6 +1094,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
939
1094
|
syncBlockStore,
|
|
940
1095
|
api,
|
|
941
1096
|
confirmationTransactionRef,
|
|
1097
|
+
ctx,
|
|
942
1098
|
bodiedSyncBlockRemoved,
|
|
943
1099
|
bodiedSyncBlockAdded,
|
|
944
1100
|
extensionFlagShown
|
|
@@ -962,6 +1118,17 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
962
1118
|
if (viewMode === 'view') {
|
|
963
1119
|
return null;
|
|
964
1120
|
}
|
|
1121
|
+
if (options !== null && options !== void 0 && options.onGiveFeedback) {
|
|
1122
|
+
const feedbackContexts = trs.flatMap(tr => {
|
|
1123
|
+
const feedbackContext = tr.getMeta(syncedBlockPromptedFeedbackMetaKey);
|
|
1124
|
+
return feedbackContext ? [feedbackContext] : [];
|
|
1125
|
+
});
|
|
1126
|
+
if (feedbackContexts.length > 0 && expValEqualsNoExposure('platform_editor_sync_block_activation', 'isEnabled', true)) {
|
|
1127
|
+
feedbackContexts.forEach(feedbackContext => {
|
|
1128
|
+
ctx.handleAppliedFeedback(feedbackContext);
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
965
1132
|
|
|
966
1133
|
// Update source sync block cache for user-initiated changes only.
|
|
967
1134
|
// Cache updates are handled here instead of in the nodeview update() so we
|
|
@@ -21,7 +21,7 @@ const onDismissed = syncBlockStore => tr => {
|
|
|
21
21
|
bodiedSyncBlockDeletionStatus: 'none'
|
|
22
22
|
});
|
|
23
23
|
};
|
|
24
|
-
export const handleBodiedSyncBlockRemoval = (bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef, deletionReason, mechanism) => {
|
|
24
|
+
export const handleBodiedSyncBlockRemoval = (bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef, deletionReason, mechanism, feedbackCallbacks) => {
|
|
25
25
|
// Clear potential old pending deletion to retreat the deletion as first attempt
|
|
26
26
|
syncBlockStore.sourceManager.clearPendingDeletion();
|
|
27
27
|
|
|
@@ -54,6 +54,7 @@ export const handleBodiedSyncBlockRemoval = (bodiedSyncBlockRemoved, syncBlockSt
|
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
56
|
recomputedTr.setMeta('isConfirmedSyncBlockDeletion', true);
|
|
57
|
+
feedbackCallbacks === null || feedbackCallbacks === void 0 ? void 0 : feedbackCallbacks.onDeleteTransaction(recomputedTr);
|
|
57
58
|
if (!recomputedTr.getMeta(pmHistoryPluginKey)) {
|
|
58
59
|
// bodiedSyncBlock deletion is expected to be permanent (cannot undo)
|
|
59
60
|
// For a normal deletion (not triggered by undo), remove it from history so that it cannot be undone
|
|
@@ -69,6 +70,7 @@ export const handleBodiedSyncBlockRemoval = (bodiedSyncBlockRemoved, syncBlockSt
|
|
|
69
70
|
}
|
|
70
71
|
api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(() => {
|
|
71
72
|
const trToDispatch = confirmationTransaction.setMeta('isConfirmedSyncBlockDeletion', true);
|
|
73
|
+
feedbackCallbacks === null || feedbackCallbacks === void 0 ? void 0 : feedbackCallbacks.onDeleteTransaction(trToDispatch);
|
|
72
74
|
if (!trToDispatch.getMeta(pmHistoryPluginKey)) {
|
|
73
75
|
// bodiedSyncBlock deletion is expected to be permanent (cannot undo)
|
|
74
76
|
// For a normal deletion (not triggered by undo), remove it from history so that it cannot be undone
|
|
@@ -78,6 +80,7 @@ export const handleBodiedSyncBlockRemoval = (bodiedSyncBlockRemoved, syncBlockSt
|
|
|
78
80
|
});
|
|
79
81
|
}, success => {
|
|
80
82
|
var _api$core4;
|
|
83
|
+
feedbackCallbacks === null || feedbackCallbacks === void 0 ? void 0 : feedbackCallbacks.onDeleteCompleted(success);
|
|
81
84
|
api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions.execute(({
|
|
82
85
|
tr
|
|
83
86
|
}) => {
|
|
@@ -107,6 +110,7 @@ export const handleBodiedSyncBlockRemoval = (bodiedSyncBlockRemoved, syncBlockSt
|
|
|
107
110
|
});
|
|
108
111
|
}, () => {
|
|
109
112
|
confirmationTransactionRef.current = undefined;
|
|
113
|
+
feedbackCallbacks === null || feedbackCallbacks === void 0 ? void 0 : feedbackCallbacks.onDestroy();
|
|
110
114
|
}, mechanism);
|
|
111
115
|
return false;
|
|
112
116
|
};
|
|
@@ -26,6 +26,7 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore, isLivePage, o
|
|
|
26
26
|
if (syncBlockStore.sourceManager.isPendingCreation(syncBlockObject.node.attrs.resourceId)) {
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
|
+
const isSyncBlockActivationEnabled = expValEquals('platform_editor_sync_block_activation', 'isEnabled', true);
|
|
29
30
|
const syncBlockInstance = syncBlockStore.referenceManager.getFromCache(syncBlockObject.node.attrs.resourceId);
|
|
30
31
|
const isUnsyncedBlock = (syncBlockInstance === null || syncBlockInstance === void 0 ? void 0 : (_syncBlockInstance$er = syncBlockInstance.error) === null || _syncBlockInstance$er === void 0 ? void 0 : _syncBlockInstance$er.type) === SyncBlockError.NotFound;
|
|
31
32
|
const isErroredBlock = syncBlockInstance === null || syncBlockInstance === void 0 ? void 0 : syncBlockInstance.error;
|
|
@@ -53,7 +54,6 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore, isLivePage, o
|
|
|
53
54
|
onBlur: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(nodeType, false, className)
|
|
54
55
|
});
|
|
55
56
|
const items = [];
|
|
56
|
-
const isSyncBlockActivationEnabled = expValEquals('platform_editor_sync_block_activation', 'isEnabled', true);
|
|
57
57
|
if (isUnsyncedBlock) {
|
|
58
58
|
const deleteButton = {
|
|
59
59
|
type: 'button',
|
|
@@ -192,7 +192,8 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore, isLivePage, o
|
|
|
192
192
|
tr
|
|
193
193
|
}) => tr.setSelection(new GapCursorSelection(tr.doc.resolve(syncBlockObject.pos + syncBlockObject.node.nodeSize), Side.RIGHT)));
|
|
194
194
|
onGiveFeedback({
|
|
195
|
-
blockType: isBodiedSyncBlock ? 'source' : 'reference'
|
|
195
|
+
blockType: isBodiedSyncBlock ? 'source' : 'reference',
|
|
196
|
+
entryPoint: 'overflow-menu'
|
|
196
197
|
});
|
|
197
198
|
return true;
|
|
198
199
|
}
|
|
@@ -9,6 +9,7 @@ import { NodeSelection, Selection, TextSelection } from '@atlaskit/editor-prosem
|
|
|
9
9
|
import { findSelectedNodeOfType, removeParentNodeOfType, removeSelectedNode, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
10
10
|
import { getSourceProductFromResourceIdSafe } from '@atlaskit/editor-synced-block-provider/utils';
|
|
11
11
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
12
|
+
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
|
|
12
13
|
import { creationMetaKey, deleteMechanismMetaKey, syncedBlockPluginKey } from '../pm-plugins/main';
|
|
13
14
|
import { canBeConvertedToSyncBlock, deferDispatch, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
14
15
|
import { FLAG_ID } from '../types';
|
|
@@ -348,7 +349,11 @@ export var removeSyncedBlockAtPos = function removeSyncedBlockAtPos(api, pos) {
|
|
|
348
349
|
var node = tr.doc.nodeAt(pos);
|
|
349
350
|
if ((node === null || node === void 0 ? void 0 : node.type.name) === 'syncBlock') {
|
|
350
351
|
var _node$nodeSize;
|
|
351
|
-
|
|
352
|
+
var removeTr = tr.replace(pos, pos + ((_node$nodeSize = node === null || node === void 0 ? void 0 : node.nodeSize) !== null && _node$nodeSize !== void 0 ? _node$nodeSize : 0));
|
|
353
|
+
if (expValEqualsNoExposure('platform_editor_sync_block_activation', 'isEnabled', true)) {
|
|
354
|
+
removeTr.setMeta(deleteMechanismMetaKey, 'deleteButton');
|
|
355
|
+
}
|
|
356
|
+
return removeTr;
|
|
352
357
|
}
|
|
353
358
|
return tr;
|
|
354
359
|
});
|