@atlaskit/editor-plugin-block-controls 7.7.2 → 7.7.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.
Files changed (35) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cjs/blockControlsPlugin.js +14 -0
  3. package/dist/cjs/pm-plugins/selection-preservation/editor-commands.js +32 -0
  4. package/dist/cjs/pm-plugins/selection-preservation/plugin-key.js +8 -0
  5. package/dist/cjs/pm-plugins/selection-preservation/pm-plugin.js +99 -0
  6. package/dist/cjs/pm-plugins/selection-preservation/types.js +5 -0
  7. package/dist/cjs/pm-plugins/selection-preservation/utils.js +24 -0
  8. package/dist/cjs/ui/drag-handle.js +182 -62
  9. package/dist/es2019/blockControlsPlugin.js +11 -1
  10. package/dist/es2019/pm-plugins/selection-preservation/editor-commands.js +28 -0
  11. package/dist/es2019/pm-plugins/selection-preservation/plugin-key.js +2 -0
  12. package/dist/es2019/pm-plugins/selection-preservation/pm-plugin.js +92 -0
  13. package/dist/es2019/pm-plugins/selection-preservation/types.js +1 -0
  14. package/dist/es2019/pm-plugins/selection-preservation/utils.js +16 -0
  15. package/dist/es2019/ui/drag-handle.js +156 -33
  16. package/dist/esm/blockControlsPlugin.js +14 -0
  17. package/dist/esm/pm-plugins/selection-preservation/editor-commands.js +26 -0
  18. package/dist/esm/pm-plugins/selection-preservation/plugin-key.js +2 -0
  19. package/dist/esm/pm-plugins/selection-preservation/pm-plugin.js +93 -0
  20. package/dist/esm/pm-plugins/selection-preservation/types.js +1 -0
  21. package/dist/esm/pm-plugins/selection-preservation/utils.js +18 -0
  22. package/dist/esm/ui/drag-handle.js +184 -64
  23. package/dist/types/blockControlsPluginType.d.ts +12 -1
  24. package/dist/types/pm-plugins/selection-preservation/editor-commands.d.ts +13 -0
  25. package/dist/types/pm-plugins/selection-preservation/plugin-key.d.ts +3 -0
  26. package/dist/types/pm-plugins/selection-preservation/pm-plugin.d.ts +26 -0
  27. package/dist/types/pm-plugins/selection-preservation/types.d.ts +7 -0
  28. package/dist/types/pm-plugins/selection-preservation/utils.d.ts +10 -0
  29. package/dist/types-ts4.5/blockControlsPluginType.d.ts +12 -1
  30. package/dist/types-ts4.5/pm-plugins/selection-preservation/editor-commands.d.ts +13 -0
  31. package/dist/types-ts4.5/pm-plugins/selection-preservation/plugin-key.d.ts +3 -0
  32. package/dist/types-ts4.5/pm-plugins/selection-preservation/pm-plugin.d.ts +26 -0
  33. package/dist/types-ts4.5/pm-plugins/selection-preservation/types.d.ts +7 -0
  34. package/dist/types-ts4.5/pm-plugins/selection-preservation/utils.d.ts +10 -0
  35. package/package.json +4 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 7.7.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`aa5913a5d4962`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/aa5913a5d4962) -
8
+ [ux] EDITOR-2679 Fix multiselect collapsing issues for drag handle selections and block menu
9
+ - Updated dependencies
10
+
3
11
  ## 7.7.2
4
12
 
5
13
  ### Patch Changes
@@ -20,6 +20,8 @@ var _moveNodeUtils = require("./editor-commands/utils/move-node-utils");
20
20
  var _firstNodeDecPlugin = require("./pm-plugins/first-node-dec-plugin");
21
21
  var _pmPlugin = require("./pm-plugins/interaction-tracking/pm-plugin");
22
22
  var _main = require("./pm-plugins/main");
23
+ var _editorCommands = require("./pm-plugins/selection-preservation/editor-commands");
24
+ var _pmPlugin2 = require("./pm-plugins/selection-preservation/pm-plugin");
23
25
  var _getSelection = require("./pm-plugins/utils/getSelection");
24
26
  var _blockMenu = _interopRequireDefault(require("./ui/block-menu"));
25
27
  var _dragHandleMenu = require("./ui/drag-handle-menu");
@@ -45,6 +47,12 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
45
47
  plugin: _pmPlugin.createInteractionTrackingPlugin
46
48
  });
47
49
  }
50
+ if ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true)) {
51
+ pmPlugins.push({
52
+ name: 'blockControlsSelectionPreservationPlugin',
53
+ plugin: _pmPlugin2.createSelectionPreservationPlugin
54
+ });
55
+ }
48
56
 
49
57
  // platform_editor_controls note: quick insert rendering fixes
50
58
  if ((0, _toolbarFlagCheck.areToolbarFlagsEnabled)(Boolean(api === null || api === void 0 ? void 0 : api.toolbar))) {
@@ -239,6 +247,12 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
239
247
  },
240
248
  moveNodeWithBlockMenu: function moveNodeWithBlockMenu(direction) {
241
249
  return (0, _moveNodeWithBlockMenu2.moveNodeWithBlockMenu)(api, direction);
250
+ },
251
+ startPreservingSelection: function startPreservingSelection() {
252
+ return _editorCommands.startPreservingSelection;
253
+ },
254
+ stopPreservingSelection: function stopPreservingSelection() {
255
+ return _editorCommands.stopPreservingSelection;
242
256
  }
243
257
  },
244
258
  getSharedState: function getSharedState(editorState) {
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.stopPreservingSelection = exports.startPreservingSelection = void 0;
7
+ var _pluginKey = require("./plugin-key");
8
+ /**
9
+ * Start preserving the selection when a UI interaction requires it
10
+ *
11
+ * e.g., block menu open, drag-and-drop in progress
12
+ */
13
+ var startPreservingSelection = exports.startPreservingSelection = function startPreservingSelection(_ref) {
14
+ var tr = _ref.tr;
15
+ var meta = {
16
+ type: 'startPreserving'
17
+ };
18
+ return tr.setMeta(_pluginKey.selectionPreservationPluginKey, meta);
19
+ };
20
+
21
+ /**
22
+ * Stop preserving the selection when a UI interaction completes
23
+ *
24
+ * e.g., block menu closed, drag-and-drop ended
25
+ */
26
+ var stopPreservingSelection = exports.stopPreservingSelection = function stopPreservingSelection(_ref2) {
27
+ var tr = _ref2.tr;
28
+ var meta = {
29
+ type: 'stopPreserving'
30
+ };
31
+ return tr.setMeta(_pluginKey.selectionPreservationPluginKey, meta);
32
+ };
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.selectionPreservationPluginKey = void 0;
7
+ var _state = require("@atlaskit/editor-prosemirror/state");
8
+ var selectionPreservationPluginKey = exports.selectionPreservationPluginKey = new _state.PluginKey('selectionPreservationPlugin');
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.createSelectionPreservationPlugin = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _monitoring = require("@atlaskit/editor-common/monitoring");
10
+ var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
11
+ var _state = require("@atlaskit/editor-prosemirror/state");
12
+ var _editorCommands = require("./editor-commands");
13
+ var _pluginKey = require("./plugin-key");
14
+ var _utils = require("./utils");
15
+ 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; }
16
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17
+ /**
18
+ * Selection Preservation Plugin for ProseMirror Editor
19
+ *
20
+ * Solves a ProseMirror limitation where TextSelection cannot include positions at node boundaries
21
+ * (like media/images). When a selection spans text + media nodes, subsequent transactions cause
22
+ * ProseMirror to collapse the selection to the nearest inline position, excluding the media node.
23
+ * This is problematic for features like block menus and drag-and-drop that need stable multi-node
24
+ * selections while performing operations.
25
+ *
26
+ * The plugin works in three phases:
27
+ * (1) Explicitly save a selection via startPreservingSelection() when opening block menus or starting drag operations.
28
+ * (2) Map the saved selection through document changes to keep positions valid.
29
+ * (3) Detect when transactions collapse the selection and restore it via appendTransaction().
30
+ *
31
+ * Stops preserving via stopPreservingSelection() when the menu closes or operation completes.
32
+ *
33
+ * Commands: startPreservingSelection() to begin preservation, stopPreservingSelection() to end it.
34
+ *
35
+ * NOTE: Only use when the UI blocks user selection changes. For example: when a block menu overlay
36
+ * is open (editor becomes non-interactive), during drag-and-drop operations (user is mid-drag), or
37
+ * when modal dialogs are active. In these states, any selection changes are from ProseMirror's
38
+ * internal behavior (not user input) and should be prevented. Do not use during normal editing.
39
+ */
40
+ var createSelectionPreservationPlugin = exports.createSelectionPreservationPlugin = function createSelectionPreservationPlugin() {
41
+ return new _safePlugin.SafePlugin({
42
+ key: _pluginKey.selectionPreservationPluginKey,
43
+ state: {
44
+ init: function init() {
45
+ return {
46
+ preservedSelection: undefined
47
+ };
48
+ },
49
+ apply: function apply(tr, pluginState) {
50
+ var meta = (0, _utils.getSelectionPreservationMeta)(tr);
51
+ var newState = _objectSpread({}, pluginState);
52
+ if ((meta === null || meta === void 0 ? void 0 : meta.type) === 'startPreserving') {
53
+ newState.preservedSelection = new _state.TextSelection(tr.selection.$from, tr.selection.$to);
54
+ } else if ((meta === null || meta === void 0 ? void 0 : meta.type) === 'stopPreserving') {
55
+ newState.preservedSelection = undefined;
56
+ }
57
+ if (newState.preservedSelection && tr.docChanged) {
58
+ var mapped = new _state.TextSelection(newState.preservedSelection.$from, newState.preservedSelection.$to);
59
+ mapped.map(tr.doc, tr.mapping);
60
+ if (mapped.from >= 0 && mapped.to <= tr.doc.content.size && mapped.from !== mapped.to) {
61
+ newState.preservedSelection = mapped;
62
+ } else if (mapped.from === mapped.to) {
63
+ // If selection has collapsed to a cursor, e.g. after deleting the selection, stop preserving
64
+ newState.preservedSelection = undefined;
65
+ }
66
+ }
67
+ return newState;
68
+ }
69
+ },
70
+ appendTransaction: function appendTransaction(transactions, _oldState, newState) {
71
+ var pluginState = _pluginKey.selectionPreservationPluginKey.getState(newState);
72
+ var savedSel = pluginState === null || pluginState === void 0 ? void 0 : pluginState.preservedSelection;
73
+ if (!savedSel) {
74
+ return null;
75
+ }
76
+ if ((0, _utils.hasUserSelectionChange)(transactions)) {
77
+ // Auto-stop if user explicitly changes selection
78
+ return (0, _editorCommands.stopPreservingSelection)({
79
+ tr: newState.tr
80
+ });
81
+ }
82
+ var currSel = newState.selection;
83
+ var wasEmptySelection = savedSel.from === savedSel.to;
84
+ var selectionUnchanged = currSel.from === savedSel.from && currSel.to === savedSel.to;
85
+ var selectionInvalid = savedSel.from < 0 || savedSel.to > newState.doc.content.size;
86
+ if (wasEmptySelection || selectionUnchanged || selectionInvalid) {
87
+ return null;
88
+ }
89
+ try {
90
+ return newState.tr.setSelection(_state.TextSelection.create(newState.doc, savedSel.from, savedSel.to));
91
+ } catch (error) {
92
+ (0, _monitoring.logException)(error, {
93
+ location: 'editor-plugin-block-controls/SelectionPreservationPlugin'
94
+ });
95
+ }
96
+ return null;
97
+ }
98
+ });
99
+ };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.hasUserSelectionChange = exports.getSelectionPreservationMeta = void 0;
7
+ var _pluginKey = require("./plugin-key");
8
+ /**
9
+ * Detects if any of the transactions include user-driven selection changes.
10
+ *
11
+ * @param transactions The list of transactions to check.
12
+ * @returns True if any transaction includes a user-driven selection change, otherwise false.
13
+ */
14
+ var hasUserSelectionChange = exports.hasUserSelectionChange = function hasUserSelectionChange(transactions) {
15
+ return transactions.some(function (tr) {
16
+ return tr.getMeta('pointer') || tr.getMeta('uiEvent') || tr.getMeta('paste') || tr.getMeta('cut') || tr.getMeta('composition') ||
17
+ // IME input
18
+ // Keyboard events that change selection
19
+ tr.getMeta('addToHistory') && tr.selectionSet;
20
+ });
21
+ };
22
+ var getSelectionPreservationMeta = exports.getSelectionPreservationMeta = function getSelectionPreservationMeta(tr) {
23
+ return tr.getMeta(_pluginKey.selectionPreservationPluginKey);
24
+ };
@@ -11,6 +11,7 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
11
11
  var _react = require("react");
12
12
  var _react2 = require("@emotion/react");
13
13
  var _bindEventListener = require("bind-event-listener");
14
+ var _browserApis = require("@atlaskit/browser-apis");
14
15
  var _analytics = require("@atlaskit/editor-common/analytics");
15
16
  var _browser = require("@atlaskit/editor-common/browser");
16
17
  var _hooks = require("@atlaskit/editor-common/hooks");
@@ -34,6 +35,7 @@ var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
34
35
  var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
35
36
  var _decorationsCommon = require("../pm-plugins/decorations-common");
36
37
  var _main = require("../pm-plugins/main");
38
+ var _pluginKey = require("../pm-plugins/selection-preservation/plugin-key");
37
39
  var _analytics2 = require("../pm-plugins/utils/analytics");
38
40
  var _dragHandlePositions = require("../pm-plugins/utils/drag-handle-positions");
39
41
  var _getSelection = require("../pm-plugins/utils/getSelection");
@@ -296,18 +298,81 @@ var getNodeMargins = function getNodeMargins(node) {
296
298
  }
297
299
  return _consts2.nodeMargins[nodeTypeName] || _consts2.nodeMargins['default'];
298
300
  };
299
- var DragHandle = exports.DragHandle = function DragHandle(_ref) {
300
- var _api$core3;
301
- var view = _ref.view,
302
- api = _ref.api,
303
- formatMessage = _ref.formatMessage,
304
- getPos = _ref.getPos,
305
- anchorName = _ref.anchorName,
306
- nodeType = _ref.nodeType,
307
- handleOptions = _ref.handleOptions,
308
- _ref$isTopLevelNode = _ref.isTopLevelNode,
309
- isTopLevelNode = _ref$isTopLevelNode === void 0 ? true : _ref$isTopLevelNode,
310
- anchorRectCache = _ref.anchorRectCache;
301
+ var isRangeSpanningMultipleNodes = function isRangeSpanningMultipleNodes(range) {
302
+ if (range.endIndex - range.startIndex <= 1) {
303
+ return false; // At most one child
304
+ }
305
+
306
+ // Count block nodes in the range, return true if more than one
307
+ var blockCount = 0;
308
+ for (var i = range.startIndex; i < range.endIndex; i++) {
309
+ if (range.parent.child(i).isBlock) {
310
+ blockCount++;
311
+ }
312
+ if (blockCount > 1) {
313
+ return true;
314
+ }
315
+ }
316
+ return false;
317
+ };
318
+ var shouldExpandSelection = function shouldExpandSelection(range, startPos) {
319
+ return !!range && isRangeSpanningMultipleNodes(range) && range.start <= startPos && range.end >= startPos + 1;
320
+ };
321
+ var calculateBlockRange = function calculateBlockRange(_ref) {
322
+ var selection = _ref.selection,
323
+ doc = _ref.doc,
324
+ resolvedStartPos = _ref.resolvedStartPos,
325
+ isShiftPressed = _ref.isShiftPressed;
326
+ if (!isShiftPressed) {
327
+ // When not pressing shift, create range including all block nodes within the selection
328
+ return selection.$from.blockRange(selection.$to);
329
+ }
330
+ if (resolvedStartPos.pos < selection.from) {
331
+ // If shift+click selecting upwards, get range from start of node to end of selection
332
+ return resolvedStartPos.blockRange(selection.$to);
333
+ }
334
+
335
+ // Shift+click selecting downwards, get range from start of selection to pos within or after node
336
+ var resolvedPosWithinOrAfterNode = doc.resolve(resolvedStartPos.pos + 1);
337
+ return selection.$from.blockRange(resolvedPosWithinOrAfterNode);
338
+ };
339
+ var createExpandedSelection = function createExpandedSelection(doc, selection, range) {
340
+ return _state.TextSelection.create(doc, Math.min(selection.from, range.start), Math.max(selection.to, range.end));
341
+ };
342
+ var createSelectionFromRange = function createSelectionFromRange(_ref2) {
343
+ var tr = _ref2.tr,
344
+ selection = _ref2.selection,
345
+ startPos = _ref2.startPos,
346
+ nodeType = _ref2.nodeType,
347
+ range = _ref2.range,
348
+ api = _ref2.api;
349
+ if (range && shouldExpandSelection(range, startPos)) {
350
+ var expandedSelection = createExpandedSelection(tr.doc, selection, range);
351
+ if (!expandedSelection.eq(tr.selection)) {
352
+ tr.setSelection(expandedSelection);
353
+ }
354
+ return tr;
355
+ }
356
+ var node = tr.doc.nodeAt(startPos);
357
+ var isEmptyNode = (node === null || node === void 0 ? void 0 : node.content.size) === 0;
358
+ if (isEmptyNode && node.type.name !== 'paragraph') {
359
+ tr.setSelection(new _state.NodeSelection(tr.doc.resolve(startPos)));
360
+ return tr;
361
+ }
362
+ return (0, _getSelection.selectNode)(tr, startPos, nodeType, api);
363
+ };
364
+ var DragHandle = exports.DragHandle = function DragHandle(_ref3) {
365
+ var _api$core4;
366
+ var view = _ref3.view,
367
+ api = _ref3.api,
368
+ formatMessage = _ref3.formatMessage,
369
+ getPos = _ref3.getPos,
370
+ anchorName = _ref3.anchorName,
371
+ nodeType = _ref3.nodeType,
372
+ handleOptions = _ref3.handleOptions,
373
+ _ref3$isTopLevelNode = _ref3.isTopLevelNode,
374
+ isTopLevelNode = _ref3$isTopLevelNode === void 0 ? true : _ref3$isTopLevelNode,
375
+ anchorRectCache = _ref3.anchorRectCache;
311
376
  var buttonRef = (0, _react.useRef)(null);
312
377
  var _useState = (0, _react.useState)(false),
313
378
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
@@ -368,14 +433,69 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
368
433
  }
369
434
  }
370
435
  }, [anchorName, nodeType, view.dom]);
371
- var handleOnClick = (0, _react.useCallback)(function (e) {
436
+ var handleOnClickNew = (0, _react.useCallback)(function (e) {
372
437
  var _api$core;
438
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref4) {
439
+ var _api$analytics, _resolvedStartPos$nod, _selectionPreservatio, _api$blockControls, _api$blockControls2;
440
+ var tr = _ref4.tr;
441
+ var startPos = getPos();
442
+ if (startPos === undefined) {
443
+ return tr;
444
+ }
445
+ var resolvedStartPos = tr.doc.resolve(startPos);
446
+ api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
447
+ eventType: _analytics.EVENT_TYPE.UI,
448
+ action: _analytics.ACTION.CLICKED,
449
+ actionSubject: _analytics.ACTION_SUBJECT.BUTTON,
450
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
451
+ attributes: {
452
+ nodeDepth: resolvedStartPos.depth,
453
+ nodeType: ((_resolvedStartPos$nod = resolvedStartPos.nodeAfter) === null || _resolvedStartPos$nod === void 0 ? void 0 : _resolvedStartPos$nod.type.name) || ''
454
+ }
455
+ })(tr);
456
+ var preservedSelection = (_selectionPreservatio = _pluginKey.selectionPreservationPluginKey.getState(view.state)) === null || _selectionPreservatio === void 0 ? void 0 : _selectionPreservatio.preservedSelection;
457
+ var selection = preservedSelection || tr.selection;
458
+ var range = calculateBlockRange({
459
+ doc: tr.doc,
460
+ selection: selection,
461
+ resolvedStartPos: resolvedStartPos,
462
+ isShiftPressed: e.shiftKey
463
+ });
464
+ tr = createSelectionFromRange({
465
+ tr: tr,
466
+ selection: selection,
467
+ startPos: startPos,
468
+ nodeType: nodeType,
469
+ range: range,
470
+ api: api
471
+ });
472
+ api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.startPreservingSelection()({
473
+ tr: tr
474
+ });
475
+ api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.toggleBlockMenu({
476
+ anchorName: anchorName,
477
+ openedViaKeyboard: false,
478
+ triggerByNode: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_synced_block', 'isEnabled', true) ? {
479
+ nodeType: nodeType,
480
+ pos: startPos,
481
+ rootPos: tr.doc.resolve(startPos).before(1)
482
+ } : undefined
483
+ })({
484
+ tr: tr
485
+ });
486
+ tr.setMeta('scrollIntoView', false);
487
+ return tr;
488
+ });
489
+ view.focus();
490
+ }, [api, view, getPos, nodeType, anchorName]);
491
+ var handleOnClick = (0, _react.useCallback)(function (e) {
492
+ var _api$core2;
373
493
  if (!isMultiSelect) {
374
494
  setDragHandleSelected(!dragHandleSelected);
375
495
  }
376
- api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref2) {
377
- var _api$blockControls$sh, _api$analytics;
378
- var tr = _ref2.tr;
496
+ api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(function (_ref5) {
497
+ var _api$blockControls$sh, _api$analytics2;
498
+ var tr = _ref5.tr;
379
499
  var startPos = getPos();
380
500
  if (startPos === undefined) {
381
501
  return tr;
@@ -404,8 +524,8 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
404
524
  rootPos: rootPos
405
525
  } : undefined;
406
526
  if (_consts2.BLOCK_MENU_ENABLED && (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) {
407
- var _api$blockControls;
408
- api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.toggleBlockMenu({
527
+ var _api$blockControls3;
528
+ api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || _api$blockControls3.commands.toggleBlockMenu({
409
529
  anchorName: anchorName,
410
530
  triggerByNode: triggerByNode,
411
531
  openedViaKeyboard: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? false : undefined
@@ -414,8 +534,8 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
414
534
  });
415
535
  e.stopPropagation();
416
536
  } else if ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true)) {
417
- var _api$blockControls2;
418
- api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.toggleBlockMenu({
537
+ var _api$blockControls4;
538
+ api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 || _api$blockControls4.commands.toggleBlockMenu({
419
539
  anchorName: anchorName,
420
540
  triggerByNode: triggerByNode,
421
541
  openedViaKeyboard: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? false : undefined
@@ -425,18 +545,18 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
425
545
  e.stopPropagation();
426
546
  }
427
547
  } else if (isTopLevelNode && $anchor.depth <= _consts2.DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH && e.shiftKey && (0, _platformFeatureFlags.fg)('platform_editor_elements_dnd_shift_click_select')) {
428
- var _api$blockControls3;
548
+ var _api$blockControls5;
429
549
  var alignAnchorHeadToSel = (0, _selection3.alignAnchorHeadInDirectionOfPos)(tr.selection, startPos);
430
550
  var selectionWithExpandedHead = (0, _selection3.expandSelectionHeadToNodeAtPos)(alignAnchorHeadToSel, startPos);
431
551
  tr.setSelection(selectionWithExpandedHead);
432
- api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || _api$blockControls3.commands.setMultiSelectPositions()({
552
+ api === null || api === void 0 || (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 || _api$blockControls5.commands.setMultiSelectPositions()({
433
553
  tr: tr
434
554
  });
435
555
  }
436
556
  var resolvedMovingNode = tr.doc.resolve(startPos);
437
557
  var maybeNode = resolvedMovingNode.nodeAfter;
438
558
  tr.setMeta('scrollIntoView', false);
439
- api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
559
+ api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.attachAnalyticsEvent({
440
560
  eventType: _analytics.EVENT_TYPE.UI,
441
561
  action: _analytics.ACTION.CLICKED,
442
562
  actionSubject: _analytics.ACTION_SUBJECT.BUTTON,
@@ -453,10 +573,10 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
453
573
  var handleKeyDown = (0, _react.useCallback)(function (e) {
454
574
  // allow user to use spacebar to select the node
455
575
  if (!e.repeat && e.key === ' ') {
456
- var _api$core2;
576
+ var _api$core3;
457
577
  var startPos = getPos();
458
- api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(function (_ref3) {
459
- var tr = _ref3.tr;
578
+ api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref6) {
579
+ var tr = _ref6.tr;
460
580
  if (startPos === undefined) {
461
581
  return tr;
462
582
  }
@@ -479,20 +599,20 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
479
599
  // return focus to editor to resume editing from caret position
480
600
  view.focus();
481
601
  }
482
- }, [getPos, api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions, isMultiSelect, view]);
602
+ }, [getPos, api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, isMultiSelect, view]);
483
603
  var handleKeyDownNew = (0, _react.useCallback)(function (e) {
484
604
  // allow user to use spacebar to select the node
485
605
  if (e.key === 'Enter' || !e.repeat && e.key === ' ') {
486
- var _api$core4;
487
- if (document.activeElement !== buttonRef.current) {
606
+ var _getDocument, _api$core5;
607
+ if (((_getDocument = (0, _browserApis.getDocument)()) === null || _getDocument === void 0 ? void 0 : _getDocument.activeElement) !== buttonRef.current) {
488
608
  return;
489
609
  }
490
610
  e.preventDefault();
491
611
  e.stopPropagation();
492
612
  var startPos = getPos();
493
- api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(function (_ref4) {
494
- var _api$blockControls4, _api$userIntent;
495
- var tr = _ref4.tr;
613
+ api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref7) {
614
+ var _api$blockControls6, _api$userIntent;
615
+ var tr = _ref7.tr;
496
616
  if (startPos === undefined) {
497
617
  return tr;
498
618
  }
@@ -506,7 +626,7 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
506
626
  pos: startPos,
507
627
  rootPos: rootPos
508
628
  } : undefined;
509
- api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 || _api$blockControls4.commands.toggleBlockMenu({
629
+ api === null || api === void 0 || (_api$blockControls6 = api.blockControls) === null || _api$blockControls6 === void 0 || _api$blockControls6.commands.toggleBlockMenu({
510
630
  anchorName: anchorName,
511
631
  triggerByNode: triggerByNode,
512
632
  openedViaKeyboard: true
@@ -521,11 +641,11 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
521
641
  } else if (e.key === 'Backspace' || e.key === 'Delete') {
522
642
  e.preventDefault();
523
643
  e.stopPropagation();
524
- api === null || api === void 0 || api.core.actions.execute(function (_ref5) {
525
- var _api$blockControls5;
526
- var tr = _ref5.tr;
644
+ api === null || api === void 0 || api.core.actions.execute(function (_ref8) {
645
+ var _api$blockControls7;
646
+ var tr = _ref8.tr;
527
647
  (0, _selection2.deleteSelectedRange)(tr);
528
- api === null || api === void 0 || (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 || _api$blockControls5.commands.toggleBlockMenu({
648
+ api === null || api === void 0 || (_api$blockControls7 = api.blockControls) === null || _api$blockControls7 === void 0 || _api$blockControls7.commands.toggleBlockMenu({
529
649
  closeMenu: true
530
650
  })({
531
651
  tr: tr
@@ -553,21 +673,21 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
553
673
  start: start
554
674
  };
555
675
  },
556
- onGenerateDragPreview: function onGenerateDragPreview(_ref6) {
676
+ onGenerateDragPreview: function onGenerateDragPreview(_ref9) {
557
677
  var _api$blockControls$sh2;
558
- var nativeSetDragImage = _ref6.nativeSetDragImage;
678
+ var nativeSetDragImage = _ref9.nativeSetDragImage;
559
679
  if (isMultiSelect) {
560
- var _api$core5;
561
- api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref7) {
562
- var tr = _ref7.tr;
680
+ var _api$core6;
681
+ api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 || _api$core6.actions.execute(function (_ref0) {
682
+ var tr = _ref0.tr;
563
683
  var handlePos = getPos();
564
684
  if (typeof handlePos !== 'number') {
565
685
  return tr;
566
686
  }
567
687
  var newHandlePosCheck = (0, _getSelection.isHandleCorrelatedToSelection)(view.state, tr.selection, handlePos);
568
688
  if (!tr.selection.empty && newHandlePosCheck) {
569
- var _api$blockControls6;
570
- api === null || api === void 0 || (_api$blockControls6 = api.blockControls) === null || _api$blockControls6 === void 0 || _api$blockControls6.commands.setMultiSelectPositions()({
689
+ var _api$blockControls8;
690
+ api === null || api === void 0 || (_api$blockControls8 = api.blockControls) === null || _api$blockControls8 === void 0 || _api$blockControls8.commands.setMultiSelectPositions()({
571
691
  tr: tr
572
692
  });
573
693
  } else if ((0, _platformFeatureFlags.fg)('platform_editor_elements_dnd_select_node_on_drag')) {
@@ -637,8 +757,8 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
637
757
  };
638
758
  }
639
759
  },
640
- render: function render(_ref8) {
641
- var container = _ref8.container;
760
+ render: function render(_ref1) {
761
+ var container = _ref1.container;
642
762
  var dom = view.dom.querySelector("[".concat((0, _domAttrName.getAnchorAttrName)(), "=\"").concat(anchorName, "\"]"));
643
763
  if (!dom) {
644
764
  return;
@@ -670,13 +790,13 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
670
790
  });
671
791
  },
672
792
  onDragStart: function onDragStart() {
673
- var _api$core6;
793
+ var _api$core7;
674
794
  if (start === undefined) {
675
795
  return;
676
796
  }
677
- api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 || _api$core6.actions.execute(function (_ref9) {
678
- var _api$blockControls$sh3, _api$blockControls7, _api$analytics2;
679
- var tr = _ref9.tr;
797
+ api === null || api === void 0 || (_api$core7 = api.core) === null || _api$core7 === void 0 || _api$core7.actions.execute(function (_ref10) {
798
+ var _api$blockControls$sh3, _api$blockControls9, _api$analytics3;
799
+ var tr = _ref10.tr;
680
800
  var nodeTypes, hasSelectedMultipleNodes;
681
801
  var resolvedMovingNode = tr.doc.resolve(start);
682
802
  var maybeNode = resolvedMovingNode.nodeAfter;
@@ -689,11 +809,11 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
689
809
  nodeTypes = maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name;
690
810
  hasSelectedMultipleNodes = false;
691
811
  }
692
- api === null || api === void 0 || (_api$blockControls7 = api.blockControls) === null || _api$blockControls7 === void 0 || _api$blockControls7.commands.setNodeDragged(getPos, anchorName, nodeType)({
812
+ api === null || api === void 0 || (_api$blockControls9 = api.blockControls) === null || _api$blockControls9 === void 0 || _api$blockControls9.commands.setNodeDragged(getPos, anchorName, nodeType)({
693
813
  tr: tr
694
814
  });
695
815
  tr.setMeta('scrollIntoView', false);
696
- api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.attachAnalyticsEvent({
816
+ api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.attachAnalyticsEvent({
697
817
  eventType: _analytics.EVENT_TYPE.UI,
698
818
  action: _analytics.ACTION.DRAGGED,
699
819
  actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
@@ -987,7 +1107,7 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
987
1107
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
988
1108
  ,
989
1109
  style: !(0, _experiments.editorExperiment)('platform_editor_controls', 'variant1') ? (0, _experiments.editorExperiment)('platform_editor_block_control_optimise_render', true) ? positionStyles : positionStylesOld : {},
990
- onClick: handleOnClick,
1110
+ onClick: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true) ? handleOnClickNew : handleOnClick,
991
1111
  onKeyDown: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true) && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? handleKeyDownNew : handleKeyDown
992
1112
  // eslint-disable-next-line @atlaskit/design-system/no-direct-use-of-web-platform-drag-and-drop
993
1113
  ,
@@ -1072,15 +1192,15 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
1072
1192
  var render = isTooltip ? buttonWithTooltip() : renderButton();
1073
1193
  return (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1') ? stickyRender : render;
1074
1194
  };
1075
- var DragHandleWithVisibility = exports.DragHandleWithVisibility = function DragHandleWithVisibility(_ref0) {
1076
- var view = _ref0.view,
1077
- api = _ref0.api,
1078
- formatMessage = _ref0.formatMessage,
1079
- getPos = _ref0.getPos,
1080
- anchorName = _ref0.anchorName,
1081
- nodeType = _ref0.nodeType,
1082
- handleOptions = _ref0.handleOptions,
1083
- anchorRectCache = _ref0.anchorRectCache;
1195
+ var DragHandleWithVisibility = exports.DragHandleWithVisibility = function DragHandleWithVisibility(_ref11) {
1196
+ var view = _ref11.view,
1197
+ api = _ref11.api,
1198
+ formatMessage = _ref11.formatMessage,
1199
+ getPos = _ref11.getPos,
1200
+ anchorName = _ref11.anchorName,
1201
+ nodeType = _ref11.nodeType,
1202
+ handleOptions = _ref11.handleOptions,
1203
+ anchorRectCache = _ref11.anchorRectCache;
1084
1204
  return (0, _react2.jsx)(_visibilityContainer.VisibilityContainer, {
1085
1205
  api: api
1086
1206
  }, (0, _react2.jsx)(DragHandle, {
@@ -12,6 +12,8 @@ import { canMoveNodeUpOrDown } from './editor-commands/utils/move-node-utils';
12
12
  import { firstNodeDecPlugin } from './pm-plugins/first-node-dec-plugin';
13
13
  import { createInteractionTrackingPlugin, interactionTrackingPluginKey } from './pm-plugins/interaction-tracking/pm-plugin';
14
14
  import { createPlugin, key } from './pm-plugins/main';
15
+ import { startPreservingSelection, stopPreservingSelection } from './pm-plugins/selection-preservation/editor-commands';
16
+ import { createSelectionPreservationPlugin } from './pm-plugins/selection-preservation/pm-plugin';
15
17
  import { selectNode } from './pm-plugins/utils/getSelection';
16
18
  import BlockMenu from './ui/block-menu';
17
19
  import { DragHandleMenu } from './ui/drag-handle-menu';
@@ -34,6 +36,12 @@ export const blockControlsPlugin = ({
34
36
  plugin: createInteractionTrackingPlugin
35
37
  });
36
38
  }
39
+ if (expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true)) {
40
+ pmPlugins.push({
41
+ name: 'blockControlsSelectionPreservationPlugin',
42
+ plugin: createSelectionPreservationPlugin
43
+ });
44
+ }
37
45
 
38
46
  // platform_editor_controls note: quick insert rendering fixes
39
47
  if (areToolbarFlagsEnabled(Boolean(api === null || api === void 0 ? void 0 : api.toolbar))) {
@@ -233,7 +241,9 @@ export const blockControlsPlugin = ({
233
241
  },
234
242
  moveNodeWithBlockMenu: direction => {
235
243
  return moveNodeWithBlockMenu(api, direction);
236
- }
244
+ },
245
+ startPreservingSelection: () => startPreservingSelection,
246
+ stopPreservingSelection: () => stopPreservingSelection
237
247
  },
238
248
  getSharedState(editorState) {
239
249
  var _key$getState$isMenuO, _key$getState, _key$getState$menuTri, _key$getState2, _key$getState$menuTri2, _key$getState3, _key$getState$blockMe, _key$getState4, _key$getState$activeN, _key$getState5, _key$getState$activeD, _key$getState6, _key$getState$isDragg, _key$getState7, _key$getState$isPMDra, _key$getState8, _key$getState$multiSe, _key$getState9, _key$getState$isShift, _key$getState0, _key$getState$lastDra, _key$getState1, _interactionTrackingP, _key$getState$isSelec, _key$getState10;