@atlaskit/editor-plugin-block-controls 2.23.0 → 2.24.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 CHANGED
@@ -1,5 +1,29 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 2.24.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#111465](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/111465)
8
+ [`c0cbae02ded12`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/c0cbae02ded12) -
9
+ [ux] Expand existing multi-node selection when dragging handle
10
+
11
+ ### Patch Changes
12
+
13
+ - [#109402](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/109402)
14
+ [`a8c334f52bb60`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/a8c334f52bb60) -
15
+ Fix multi-select bug when dragging onto the handle replaces text
16
+ - Updated dependencies
17
+
18
+ ## 2.23.1
19
+
20
+ ### Patch Changes
21
+
22
+ - [#112350](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/112350)
23
+ [`75d73ae5c1963`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/75d73ae5c1963) -
24
+ Pressing move right shortcut on layout column should not move the cursor to the next node
25
+ - Updated dependencies
26
+
3
27
  ## 2.23.0
4
28
 
5
29
  ### Minor Changes
@@ -5,12 +5,17 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.blockControlsPlugin = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
8
9
  var _react = _interopRequireDefault(require("react"));
10
+ var _selection = require("@atlaskit/editor-common/selection");
11
+ var _state = require("@atlaskit/editor-prosemirror/state");
9
12
  var _moveNode = require("./editor-commands/move-node");
10
13
  var _moveToLayout = require("./editor-commands/move-to-layout");
11
14
  var _main = require("./pm-plugins/main");
12
15
  var _dragHandleMenu = require("./ui/drag-handle-menu");
13
16
  var _globalStyles = require("./ui/global-styles");
17
+ 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; }
18
+ 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; }
14
19
  var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPlugin(_ref) {
15
20
  var api = _ref.api;
16
21
  return {
@@ -31,14 +36,15 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
31
36
  showDragHandleAt: function showDragHandleAt(pos, anchorName, nodeType, handleOptions) {
32
37
  return function (_ref3) {
33
38
  var tr = _ref3.tr;
34
- tr.setMeta(_main.key, {
39
+ var currMeta = tr.getMeta(_main.key);
40
+ tr.setMeta(_main.key, _objectSpread(_objectSpread({}, currMeta), {}, {
35
41
  activeNode: {
36
42
  pos: pos,
37
43
  anchorName: anchorName,
38
44
  nodeType: nodeType,
39
45
  handleOptions: handleOptions
40
46
  }
41
- });
47
+ }));
42
48
  return tr;
43
49
  };
44
50
  },
@@ -49,20 +55,52 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
49
55
  if (pos === undefined) {
50
56
  return tr;
51
57
  }
52
- tr.setMeta(_main.key, {
58
+ var currMeta = tr.getMeta(_main.key);
59
+ tr.setMeta(_main.key, _objectSpread(_objectSpread({}, currMeta), {}, {
53
60
  isDragging: true,
54
61
  activeNode: {
55
62
  pos: pos,
56
63
  anchorName: anchorName,
57
64
  nodeType: nodeType
58
65
  }
66
+ }));
67
+ return tr;
68
+ };
69
+ },
70
+ setMultiSelectPositions: function setMultiSelectPositions() {
71
+ return function (_ref5) {
72
+ var _api$selection;
73
+ var tr = _ref5.tr;
74
+ var _tr$selection = tr.selection,
75
+ userAnchor = _tr$selection.anchor,
76
+ userHead = _tr$selection.head;
77
+ var _expandSelectionBound = (0, _selection.expandSelectionBounds)(tr.selection.$anchor, tr.selection.$head),
78
+ expandedAnchor = _expandSelectionBound.$anchor,
79
+ expandedHead = _expandSelectionBound.$head;
80
+ api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || _api$selection.commands.setManualSelection(expandedAnchor.pos, expandedHead.pos)({
81
+ tr: tr
59
82
  });
83
+ // this is to normalise the selection's boundaries to inline positions, preventing it from collapsing
84
+ var expandedNormalisedSel = _state.TextSelection.between(expandedAnchor, expandedHead);
85
+ tr.setSelection(expandedNormalisedSel);
86
+ var multiSelectDnD = {
87
+ anchor: expandedAnchor.pos,
88
+ head: expandedHead.pos,
89
+ textAnchor: expandedNormalisedSel.anchor,
90
+ textHead: expandedNormalisedSel.head,
91
+ userAnchor: userAnchor,
92
+ userHead: userHead
93
+ };
94
+ var currMeta = tr.getMeta(_main.key);
95
+ tr.setMeta(_main.key, _objectSpread(_objectSpread({}, currMeta), {}, {
96
+ multiSelectDnD: multiSelectDnD
97
+ }));
60
98
  return tr;
61
99
  };
62
100
  }
63
101
  },
64
102
  getSharedState: function getSharedState(editorState) {
65
- var _key$getState$isMenuO, _key$getState, _key$getState$activeN, _key$getState2, _key$getState$isDragg, _key$getState3, _key$getState$isPMDra, _key$getState4;
103
+ var _key$getState$isMenuO, _key$getState, _key$getState$activeN, _key$getState2, _key$getState$isDragg, _key$getState3, _key$getState$isPMDra, _key$getState4, _key$getState$multiSe, _key$getState5;
66
104
  if (!editorState) {
67
105
  return undefined;
68
106
  }
@@ -70,7 +108,8 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
70
108
  isMenuOpen: (_key$getState$isMenuO = (_key$getState = _main.key.getState(editorState)) === null || _key$getState === void 0 ? void 0 : _key$getState.isMenuOpen) !== null && _key$getState$isMenuO !== void 0 ? _key$getState$isMenuO : false,
71
109
  activeNode: (_key$getState$activeN = (_key$getState2 = _main.key.getState(editorState)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.activeNode) !== null && _key$getState$activeN !== void 0 ? _key$getState$activeN : undefined,
72
110
  isDragging: (_key$getState$isDragg = (_key$getState3 = _main.key.getState(editorState)) === null || _key$getState3 === void 0 ? void 0 : _key$getState3.isDragging) !== null && _key$getState$isDragg !== void 0 ? _key$getState$isDragg : false,
73
- isPMDragging: (_key$getState$isPMDra = (_key$getState4 = _main.key.getState(editorState)) === null || _key$getState4 === void 0 ? void 0 : _key$getState4.isPMDragging) !== null && _key$getState$isPMDra !== void 0 ? _key$getState$isPMDra : false
111
+ isPMDragging: (_key$getState$isPMDra = (_key$getState4 = _main.key.getState(editorState)) === null || _key$getState4 === void 0 ? void 0 : _key$getState4.isPMDragging) !== null && _key$getState$isPMDra !== void 0 ? _key$getState$isPMDra : false,
112
+ multiSelectDnD: (_key$getState$multiSe = (_key$getState5 = _main.key.getState(editorState)) === null || _key$getState5 === void 0 ? void 0 : _key$getState5.multiSelectDnD) !== null && _key$getState$multiSe !== void 0 ? _key$getState$multiSe : undefined
74
113
  };
75
114
  },
76
115
  contentComponent: function contentComponent() {
@@ -24,6 +24,7 @@ var _fireAnalytics = require("../pm-plugins/utils/fire-analytics");
24
24
  var _getNestedNodePosition = require("../pm-plugins/utils/getNestedNodePosition");
25
25
  var _getSelection = require("../pm-plugins/utils/getSelection");
26
26
  var _removeFromSource = require("../pm-plugins/utils/remove-from-source");
27
+ var _selection2 = require("../pm-plugins/utils/selection");
27
28
  var _validation = require("../pm-plugins/utils/validation");
28
29
  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; }
29
30
  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; }
@@ -136,7 +137,8 @@ var moveNodeViaShortcut = exports.moveNodeViaShortcut = function moveNodeViaShor
136
137
 
137
138
  // if the current node is the last node, don't do anything
138
139
  if (_index >= parent.childCount - 1) {
139
- return false;
140
+ // prevent event propagation to avoid moving the cursor and still select the node
141
+ return true;
140
142
  }
141
143
  var moveToEnd = _index === parent.childCount - 2;
142
144
  moveToPos = moveToEnd ? $pos.before() : selection.to + ((nextNode === null || nextNode === void 0 ? void 0 : nextNode.nodeSize) || 1);
@@ -219,26 +221,28 @@ var moveNode = exports.moveNode = function moveNode(api) {
219
221
  var formatMessage = arguments.length > 3 ? arguments[3] : undefined;
220
222
  return function (_ref6) {
221
223
  var tr = _ref6.tr;
222
- var isMultiSelect = (0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true, {
223
- exposure: true
224
- });
225
- var selection = tr.selection;
226
- var selectionFrom = selection.$from.pos;
227
- var selectionTo = selection.$to.pos;
224
+ if (!api) {
225
+ return tr;
226
+ }
228
227
  var handleNode = tr.doc.nodeAt(start);
229
228
  if (!handleNode) {
230
229
  return tr;
231
230
  }
232
231
  var sliceFrom = start;
233
232
  var sliceTo;
233
+ var isMultiSelect = (0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true, {
234
+ exposure: true
235
+ });
234
236
  if (isMultiSelect) {
235
237
  var _handleNode$nodeSize;
236
- // //If the handle position sits within the Editor selection, we will move all nodes that sit in that selection
237
- var useSelection = sliceFrom >= selectionFrom - 1 && sliceFrom <= selectionTo;
238
- sliceFrom = useSelection ? selectionFrom : start;
238
+ var _getMultiSelectionIfP = (0, _selection2.getMultiSelectionIfPosInside)(api, start),
239
+ anchor = _getMultiSelectionIfP.anchor,
240
+ head = _getMultiSelectionIfP.head;
241
+ var inSelection = anchor !== undefined && head !== undefined;
242
+ sliceFrom = inSelection ? Math.min(anchor, head) : start;
239
243
  var handleSize = (_handleNode$nodeSize = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize !== void 0 ? _handleNode$nodeSize : 1;
240
244
  var handleEnd = sliceFrom + handleSize;
241
- sliceTo = useSelection ? selectionTo : handleEnd;
245
+ sliceTo = inSelection ? Math.max(anchor, head) : handleEnd;
242
246
  } else {
243
247
  var _handleNode$nodeSize2;
244
248
  var size = (_handleNode$nodeSize2 = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize2 !== void 0 ? _handleNode$nodeSize2 : 1;
@@ -14,6 +14,7 @@ var _checkFragment = require("../pm-plugins/utils/check-fragment");
14
14
  var _consts = require("../pm-plugins/utils/consts");
15
15
  var _fireAnalytics = require("../pm-plugins/utils/fire-analytics");
16
16
  var _removeFromSource = require("../pm-plugins/utils/remove-from-source");
17
+ var _selection = require("../pm-plugins/utils/selection");
17
18
  var _updateColumnWidths = require("../pm-plugins/utils/update-column-widths");
18
19
  var _validation = require("../pm-plugins/utils/validation");
19
20
  var _consts2 = require("../ui/consts");
@@ -161,7 +162,7 @@ var insertToDestination = function insertToDestination(tr, to, sourceContent, to
161
162
  * Check if the node at `from` can be moved to node at `to` to create/expand a layout.
162
163
  * Returns the source and destination nodes and positions if it's a valid move, otherwise, undefined
163
164
  */
164
- var canMoveToLayout = function canMoveToLayout(from, to, tr) {
165
+ var canMoveToLayout = function canMoveToLayout(api, from, to, tr) {
165
166
  if (from === to) {
166
167
  return;
167
168
  }
@@ -193,17 +194,12 @@ var canMoveToLayout = function canMoveToLayout(from, to, tr) {
193
194
  var sourceFrom = from;
194
195
  var sourceTo = from + sourceContent.nodeSize;
195
196
  if (isMultiSelect) {
196
- var _tr$selection$$from$n;
197
- // Selection often starts from the content of the node (e.g. to show text selection properly),
198
- // so we need to trace back to the start of the node instead
199
- var contentStartPos = tr.selection.$from.nodeAfter && ((_tr$selection$$from$n = tr.selection.$from.nodeAfter) === null || _tr$selection$$from$n === void 0 ? void 0 : _tr$selection$$from$n.type.name) !== 'text' ? tr.selection.$from.pos : tr.selection.$from.before();
200
-
201
- // If the handle position sits within the Editor selection, we will move all nodes that sit in that selection
202
- // handle position is the same as `from` position
203
- var useSelection = from >= contentStartPos && from <= tr.selection.to;
204
- if (useSelection) {
205
- sourceFrom = contentStartPos;
206
- sourceTo = tr.selection.to;
197
+ var _getMultiSelectionIfP = (0, _selection.getMultiSelectionIfPosInside)(api, from),
198
+ anchor = _getMultiSelectionIfP.anchor,
199
+ head = _getMultiSelectionIfP.head;
200
+ if (anchor && head) {
201
+ sourceFrom = Math.min(anchor, head);
202
+ sourceTo = Math.max(anchor, head);
207
203
  sourceContent = tr.doc.slice(sourceFrom, sourceTo).content;
208
204
 
209
205
  // TODO: this might become expensive for large content, consider removing it if check has been done beforehand
@@ -291,7 +287,10 @@ var moveToLayout = exports.moveToLayout = function moveToLayout(api) {
291
287
  return function (from, to, options) {
292
288
  return function (_ref7) {
293
289
  var tr = _ref7.tr;
294
- var canMove = canMoveToLayout(from, to, tr);
290
+ if (!api) {
291
+ return tr;
292
+ }
293
+ var canMove = canMoveToLayout(api, from, to, tr);
295
294
  if (!canMove) {
296
295
  return tr;
297
296
  }
@@ -78,8 +78,24 @@ var destroyFn = function destroyFn(api, editorView) {
78
78
  }
79
79
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref3) {
80
80
  var tr = _ref3.tr;
81
- var _ref4 = source.data,
82
- start = _ref4.start;
81
+ if ((0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true)) {
82
+ var _api$blockControls, _api$selection;
83
+ var _ref4 = (api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
84
+ multiSelectDnD = _ref4.multiSelectDnD;
85
+ // Restore the users initial Editor selection when the drop completes
86
+ if (multiSelectDnD) {
87
+ // If the TextSelection between the drag start and end has changed, the document has changed, and we should not reapply the last selection
88
+ var expandedSelectionUnchanged = multiSelectDnD.textAnchor === tr.selection.anchor && multiSelectDnD.textHead === tr.selection.head;
89
+ if (expandedSelectionUnchanged) {
90
+ tr.setSelection(_state.TextSelection.create(tr.doc, multiSelectDnD.userAnchor, multiSelectDnD.userHead));
91
+ }
92
+ }
93
+ api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || _api$selection.commands.clearManualSelection()({
94
+ tr: tr
95
+ });
96
+ }
97
+ var _ref5 = source.data,
98
+ start = _ref5.start;
83
99
  // if no drop targets are rendered, assume that drop is invalid
84
100
  if (location.current.dropTargets.length === 0) {
85
101
  var _api$analytics2;
@@ -115,13 +131,15 @@ var initialState = {
115
131
  editorWidthRight: 0,
116
132
  isResizerResizing: false,
117
133
  isDocSizeLimitEnabled: null,
118
- isPMDragging: false
134
+ isPMDragging: false,
135
+ multiSelectDnD: undefined
119
136
  };
120
137
  var newApply = exports.newApply = function newApply(api, formatMessage, tr, currentState, newState, flags, nodeViewPortalProviderAPI, anchorRectCache) {
121
- var _meta$activeNode, _activeNode, _activeNode2, _meta$activeNode$hand, _meta$isDragging, _meta$isDragging2, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging;
138
+ var _meta$activeNode, _activeNode, _activeNode2, _meta$activeNode$hand, _meta$isDragging, _meta$isDragging2, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging, _meta$multiSelectDnD;
122
139
  var activeNode = currentState.activeNode,
123
140
  decorations = currentState.decorations,
124
- isResizerResizing = currentState.isResizerResizing;
141
+ isResizerResizing = currentState.isResizerResizing,
142
+ multiSelectDnD = currentState.multiSelectDnD;
125
143
  var editorHeight = currentState.editorHeight,
126
144
  editorWidthLeft = currentState.editorWidthLeft,
127
145
  editorWidthRight = currentState.editorWidthRight,
@@ -130,7 +148,7 @@ var newApply = exports.newApply = function newApply(api, formatMessage, tr, curr
130
148
  isPMDragging = currentState.isPMDragging;
131
149
  var isActiveNodeDeleted = false;
132
150
 
133
- // Remap existing decorations and activeNode when steps exist
151
+ // When steps exist, remap existing decorations, activeNode and multi select positions
134
152
  if (tr.docChanged) {
135
153
  decorations = decorations.map(tr.mapping, tr.doc);
136
154
  if (activeNode) {
@@ -142,10 +160,17 @@ var newApply = exports.newApply = function newApply(api, formatMessage, tr, curr
142
160
  nodeType: activeNode.nodeType
143
161
  };
144
162
  }
163
+ if (multiSelectDnD && flags.isMultiSelectEnabled) {
164
+ multiSelectDnD.anchor = tr.mapping.map(multiSelectDnD.anchor);
165
+ multiSelectDnD.head = tr.mapping.map(multiSelectDnD.head);
166
+ }
145
167
  }
146
168
  var meta = tr.getMeta(key);
147
169
  var resizerMeta = tr.getMeta('is-resizer-resizing');
148
170
  isResizerResizing = resizerMeta !== null && resizerMeta !== void 0 ? resizerMeta : isResizerResizing;
171
+ if (multiSelectDnD && flags.isMultiSelectEnabled) {
172
+ multiSelectDnD = (meta === null || meta === void 0 ? void 0 : meta.isDragging) === false ? undefined : multiSelectDnD;
173
+ }
149
174
  var _getTrMetadata = (0, _transactions.getTrMetadata)(tr),
150
175
  from = _getTrMetadata.from,
151
176
  to = _getTrMetadata.to,
@@ -245,7 +270,8 @@ var newApply = exports.newApply = function newApply(api, formatMessage, tr, curr
245
270
  editorWidthRight: (_meta$editorWidthRigh = meta === null || meta === void 0 ? void 0 : meta.editorWidthRight) !== null && _meta$editorWidthRigh !== void 0 ? _meta$editorWidthRigh : editorWidthRight,
246
271
  isResizerResizing: isResizerResizing,
247
272
  isDocSizeLimitEnabled: initialState.isDocSizeLimitEnabled,
248
- isPMDragging: (_meta$isPMDragging = meta === null || meta === void 0 ? void 0 : meta.isPMDragging) !== null && _meta$isPMDragging !== void 0 ? _meta$isPMDragging : isPMDragging
273
+ isPMDragging: (_meta$isPMDragging = meta === null || meta === void 0 ? void 0 : meta.isPMDragging) !== null && _meta$isPMDragging !== void 0 ? _meta$isPMDragging : isPMDragging,
274
+ multiSelectDnD: (_meta$multiSelectDnD = meta === null || meta === void 0 ? void 0 : meta.multiSelectDnD) !== null && _meta$multiSelectDnD !== void 0 ? _meta$multiSelectDnD : multiSelectDnD
249
275
  };
250
276
  };
251
277
  var oldApply = exports.oldApply = function oldApply(api, formatMessage, tr, currentState, oldState, newState, flags, nodeViewPortalProviderAPI, anchorRectCache) {
@@ -289,8 +315,8 @@ var oldApply = exports.oldApply = function oldApply(api, formatMessage, tr, curr
289
315
  }
290
316
  var decsLength = isNestedEnabled ? decorations.find(undefined, undefined, function (spec) {
291
317
  return spec.type === 'node-decoration';
292
- }).length : decorations.find().filter(function (_ref5) {
293
- var spec = _ref5.spec;
318
+ }).length : decorations.find().filter(function (_ref6) {
319
+ var spec = _ref6.spec;
294
320
  return spec.type !== 'drag-handle';
295
321
  }).length;
296
322
  var isDecsMissing = false;
@@ -328,7 +354,7 @@ var oldApply = exports.oldApply = function oldApply(api, formatMessage, tr, curr
328
354
  var newNodeDecs = (0, _decorationsAnchor.nodeDecorations)(newState);
329
355
  decorations = decorations.add(newState.doc, (0, _toConsumableArray2.default)(newNodeDecs));
330
356
  if (activeNode && !(meta !== null && meta !== void 0 && meta.nodeMoved) && !isDecsMissing) {
331
- var _meta$activeNode$pos, _meta$activeNode3, _ref6, _meta$activeNode$anch, _meta$activeNode4, _decAtPos$spec, _ref7, _meta$activeNode$node, _meta$activeNode5, _decAtPos$spec2, _meta$activeNode6;
357
+ var _meta$activeNode$pos, _meta$activeNode3, _ref7, _meta$activeNode$anch, _meta$activeNode4, _decAtPos$spec, _ref8, _meta$activeNode$node, _meta$activeNode5, _decAtPos$spec2, _meta$activeNode6;
332
358
  var mappedPosisiton = tr.mapping.map(activeNode.pos);
333
359
  var prevMappedPos = oldState.tr.mapping.map(activeNode.pos);
334
360
 
@@ -347,7 +373,7 @@ var oldApply = exports.oldApply = function oldApply(api, formatMessage, tr, curr
347
373
  var decAtPos = newNodeDecs.find(function (dec) {
348
374
  return dec.from === mappedPosisiton;
349
375
  });
350
- var draghandleDec = (0, _decorationsDragHandle.dragHandleDecoration)(api, formatMessage, (_meta$activeNode$pos = meta === null || meta === void 0 || (_meta$activeNode3 = meta.activeNode) === null || _meta$activeNode3 === void 0 ? void 0 : _meta$activeNode3.pos) !== null && _meta$activeNode$pos !== void 0 ? _meta$activeNode$pos : mappedPosisiton, (_ref6 = (_meta$activeNode$anch = meta === null || meta === void 0 || (_meta$activeNode4 = meta.activeNode) === null || _meta$activeNode4 === void 0 ? void 0 : _meta$activeNode4.anchorName) !== null && _meta$activeNode$anch !== void 0 ? _meta$activeNode$anch : decAtPos === null || decAtPos === void 0 || (_decAtPos$spec = decAtPos.spec) === null || _decAtPos$spec === void 0 ? void 0 : _decAtPos$spec.anchorName) !== null && _ref6 !== void 0 ? _ref6 : activeNode === null || activeNode === void 0 ? void 0 : activeNode.anchorName, (_ref7 = (_meta$activeNode$node = meta === null || meta === void 0 || (_meta$activeNode5 = meta.activeNode) === null || _meta$activeNode5 === void 0 ? void 0 : _meta$activeNode5.nodeType) !== null && _meta$activeNode$node !== void 0 ? _meta$activeNode$node : decAtPos === null || decAtPos === void 0 || (_decAtPos$spec2 = decAtPos.spec) === null || _decAtPos$spec2 === void 0 ? void 0 : _decAtPos$spec2.nodeType) !== null && _ref7 !== void 0 ? _ref7 : activeNode === null || activeNode === void 0 ? void 0 : activeNode.nodeType, nodeViewPortalProviderAPI, meta === null || meta === void 0 || (_meta$activeNode6 = meta.activeNode) === null || _meta$activeNode6 === void 0 ? void 0 : _meta$activeNode6.handleOptions);
376
+ var draghandleDec = (0, _decorationsDragHandle.dragHandleDecoration)(api, formatMessage, (_meta$activeNode$pos = meta === null || meta === void 0 || (_meta$activeNode3 = meta.activeNode) === null || _meta$activeNode3 === void 0 ? void 0 : _meta$activeNode3.pos) !== null && _meta$activeNode$pos !== void 0 ? _meta$activeNode$pos : mappedPosisiton, (_ref7 = (_meta$activeNode$anch = meta === null || meta === void 0 || (_meta$activeNode4 = meta.activeNode) === null || _meta$activeNode4 === void 0 ? void 0 : _meta$activeNode4.anchorName) !== null && _meta$activeNode$anch !== void 0 ? _meta$activeNode$anch : decAtPos === null || decAtPos === void 0 || (_decAtPos$spec = decAtPos.spec) === null || _decAtPos$spec === void 0 ? void 0 : _decAtPos$spec.anchorName) !== null && _ref7 !== void 0 ? _ref7 : activeNode === null || activeNode === void 0 ? void 0 : activeNode.anchorName, (_ref8 = (_meta$activeNode$node = meta === null || meta === void 0 || (_meta$activeNode5 = meta.activeNode) === null || _meta$activeNode5 === void 0 ? void 0 : _meta$activeNode5.nodeType) !== null && _meta$activeNode$node !== void 0 ? _meta$activeNode$node : decAtPos === null || decAtPos === void 0 || (_decAtPos$spec2 = decAtPos.spec) === null || _decAtPos$spec2 === void 0 ? void 0 : _decAtPos$spec2.nodeType) !== null && _ref8 !== void 0 ? _ref8 : activeNode === null || activeNode === void 0 ? void 0 : activeNode.nodeType, nodeViewPortalProviderAPI, meta === null || meta === void 0 || (_meta$activeNode6 = meta.activeNode) === null || _meta$activeNode6 === void 0 ? void 0 : _meta$activeNode6.handleOptions);
351
377
  decorations = decorations.add(newState.doc, [draghandleDec]);
352
378
  }
353
379
  }
@@ -419,8 +445,10 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl, no
419
445
  var isAdvancedLayoutEnabled = (0, _experiments.editorExperiment)('advanced_layouts', true, {
420
446
  exposure: true
421
447
  });
448
+ var isMultiSelectEnabled = (0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true);
422
449
  var flags = {
423
- isNestedEnabled: isNestedEnabled
450
+ isNestedEnabled: isNestedEnabled,
451
+ isMultiSelectEnabled: isMultiSelectEnabled
424
452
  };
425
453
  var anchorRectCache;
426
454
  if (!(0, _anchorUtils.isAnchorSupported)()) {
@@ -483,8 +511,10 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl, no
483
511
  var domPos = Math.max(view.posAtDOM(nodeElement, 0) - 1, 0);
484
512
  var nodeTarget = state.doc.nodeAt(domPos);
485
513
  var isSameNode = !!(nodeTarget && draggable !== null && draggable !== void 0 && draggable.eq(nodeTarget));
486
- if (isSameNode) {
487
- // Prevent the default drop behavior if the position is within the activeNode
514
+ var isInSelection = domPos >= state.selection.$from.pos && domPos < state.selection.$to.pos;
515
+
516
+ // Prevent the default drop behavior if the position is within the activeNode or Editor selection
517
+ if (isSameNode || isInSelection && isMultiSelectEnabled) {
488
518
  event.preventDefault();
489
519
  return true;
490
520
  }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getMultiSelectionIfPosInside = void 0;
7
+ var getMultiSelectionIfPosInside = exports.getMultiSelectionIfPosInside = function getMultiSelectionIfPosInside(api, pos) {
8
+ var _api$blockControls;
9
+ var _ref = (api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
10
+ multiSelectDnD = _ref.multiSelectDnD;
11
+ if (multiSelectDnD && multiSelectDnD.anchor >= 0 && multiSelectDnD.head >= 0) {
12
+ var multiFrom = Math.min(multiSelectDnD.anchor, multiSelectDnD.head);
13
+ var multiTo = Math.max(multiSelectDnD.anchor, multiSelectDnD.head);
14
+
15
+ // We subtract one as the handle position is before the node
16
+ return pos >= multiFrom - 1 && pos <= multiTo ? {
17
+ anchor: multiSelectDnD.anchor,
18
+ head: multiSelectDnD.head
19
+ } : {};
20
+ }
21
+ return {};
22
+ };
@@ -256,39 +256,27 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
256
256
  return;
257
257
  }
258
258
  api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref6) {
259
- var _api$blockControls, _api$analytics3;
259
+ var _api$blockControls2, _api$analytics3;
260
260
  var tr = _ref6.tr;
261
261
  var isMultiSelect = (0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true, {
262
262
  exposure: true
263
263
  });
264
- var selectionStart = start;
265
264
  if (isMultiSelect) {
266
- var selection = tr.selection;
267
- var selectionFrom = selection.$from.pos;
268
- var selectionTo = selection.$to.pos;
269
- var $selectionFrom = tr.doc.resolve(selectionFrom);
270
- var $selectionTo = tr.doc.resolve(selectionTo);
271
- selectionStart = $selectionFrom.start();
272
- var selectionEnd = $selectionTo.end();
273
265
  var handlePos = getPos();
274
266
  if (typeof handlePos !== 'number') {
275
267
  return tr;
276
268
  }
277
- var posBeforeNode = $selectionFrom.pos ? $selectionFrom.start() - 1 : $selectionFrom.pos;
278
- var shouldExpandSelection = handlePos >= posBeforeNode && handlePos <= selectionEnd;
279
- if (shouldExpandSelection) {
280
- //TODO: What happens if not a text selection?
281
- var newSelection = _state.TextSelection.create(tr.doc, selectionStart, selectionEnd);
282
- tr.setSelection(newSelection);
283
- } else {
284
- var _$selectionFrom = tr.doc.resolve(handlePos + 1);
285
- (0, _getSelection.selectNode)(tr, handlePos, _$selectionFrom.node().type.name);
269
+ if (!tr.selection.empty && handlePos >= tr.selection.$from.start() - 1 && handlePos <= tr.selection.to) {
270
+ var _api$blockControls;
271
+ api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.setMultiSelectPositions()({
272
+ tr: tr
273
+ });
286
274
  }
287
275
  }
288
- api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.setNodeDragged(getPos, anchorName, nodeType)({
276
+ api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.setNodeDragged(getPos, anchorName, nodeType)({
289
277
  tr: tr
290
278
  });
291
- var resolvedMovingNode = tr.doc.resolve(selectionStart);
279
+ var resolvedMovingNode = tr.doc.resolve(start);
292
280
  var maybeNode = resolvedMovingNode.nodeAfter;
293
281
  tr.setMeta('scrollIntoView', false);
294
282
  api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.attachAnalyticsEvent({
@@ -436,6 +424,9 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
436
424
  var message = helpDescriptors.map(function (descriptor) {
437
425
  return descriptor.keymap ? [descriptor.description, (0, _keymaps.getAriaKeyshortcuts)(descriptor.keymap)] : [descriptor.description];
438
426
  }).join('. ');
427
+ var handleOnDrop = function handleOnDrop(event) {
428
+ (0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true) && event.stopPropagation();
429
+ };
439
430
  var renderButton = function renderButton() {
440
431
  return (
441
432
  // eslint-disable-next-line @atlaskit/design-system/no-html-button
@@ -451,7 +442,10 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
451
442
  style: positionStyles,
452
443
  onClick: handleOnClick,
453
444
  onMouseDown: handleMouseDown,
454
- onKeyDown: handleKeyDown,
445
+ onKeyDown: handleKeyDown
446
+ // eslint-disable-next-line @atlaskit/design-system/no-direct-use-of-web-platform-drag-and-drop
447
+ ,
448
+ onDrop: handleOnDrop,
455
449
  "data-testid": "block-ctrl-drag-handle"
456
450
  }, (0, _react2.jsx)(_primitives.Box, {
457
451
  as: "span",
@@ -1,4 +1,6 @@
1
1
  import React from 'react';
2
+ import { expandSelectionBounds } from '@atlaskit/editor-common/selection';
3
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
2
4
  import { moveNode } from './editor-commands/move-node';
3
5
  import { moveToLayout } from './editor-commands/move-to-layout';
4
6
  import { createPlugin, key } from './pm-plugins/main';
@@ -23,7 +25,9 @@ export const blockControlsPlugin = ({
23
25
  showDragHandleAt: (pos, anchorName, nodeType, handleOptions) => ({
24
26
  tr
25
27
  }) => {
28
+ const currMeta = tr.getMeta(key);
26
29
  tr.setMeta(key, {
30
+ ...currMeta,
27
31
  activeNode: {
28
32
  pos,
29
33
  anchorName,
@@ -40,7 +44,9 @@ export const blockControlsPlugin = ({
40
44
  if (pos === undefined) {
41
45
  return tr;
42
46
  }
47
+ const currMeta = tr.getMeta(key);
43
48
  tr.setMeta(key, {
49
+ ...currMeta,
44
50
  isDragging: true,
45
51
  activeNode: {
46
52
  pos,
@@ -49,10 +55,43 @@ export const blockControlsPlugin = ({
49
55
  }
50
56
  });
51
57
  return tr;
58
+ },
59
+ setMultiSelectPositions: () => ({
60
+ tr
61
+ }) => {
62
+ var _api$selection;
63
+ const {
64
+ anchor: userAnchor,
65
+ head: userHead
66
+ } = tr.selection;
67
+ const {
68
+ $anchor: expandedAnchor,
69
+ $head: expandedHead
70
+ } = expandSelectionBounds(tr.selection.$anchor, tr.selection.$head);
71
+ api === null || api === void 0 ? void 0 : (_api$selection = api.selection) === null || _api$selection === void 0 ? void 0 : _api$selection.commands.setManualSelection(expandedAnchor.pos, expandedHead.pos)({
72
+ tr
73
+ });
74
+ // this is to normalise the selection's boundaries to inline positions, preventing it from collapsing
75
+ const expandedNormalisedSel = TextSelection.between(expandedAnchor, expandedHead);
76
+ tr.setSelection(expandedNormalisedSel);
77
+ const multiSelectDnD = {
78
+ anchor: expandedAnchor.pos,
79
+ head: expandedHead.pos,
80
+ textAnchor: expandedNormalisedSel.anchor,
81
+ textHead: expandedNormalisedSel.head,
82
+ userAnchor: userAnchor,
83
+ userHead: userHead
84
+ };
85
+ const currMeta = tr.getMeta(key);
86
+ tr.setMeta(key, {
87
+ ...currMeta,
88
+ multiSelectDnD
89
+ });
90
+ return tr;
52
91
  }
53
92
  },
54
93
  getSharedState(editorState) {
55
- var _key$getState$isMenuO, _key$getState, _key$getState$activeN, _key$getState2, _key$getState$isDragg, _key$getState3, _key$getState$isPMDra, _key$getState4;
94
+ var _key$getState$isMenuO, _key$getState, _key$getState$activeN, _key$getState2, _key$getState$isDragg, _key$getState3, _key$getState$isPMDra, _key$getState4, _key$getState$multiSe, _key$getState5;
56
95
  if (!editorState) {
57
96
  return undefined;
58
97
  }
@@ -60,7 +99,8 @@ export const blockControlsPlugin = ({
60
99
  isMenuOpen: (_key$getState$isMenuO = (_key$getState = key.getState(editorState)) === null || _key$getState === void 0 ? void 0 : _key$getState.isMenuOpen) !== null && _key$getState$isMenuO !== void 0 ? _key$getState$isMenuO : false,
61
100
  activeNode: (_key$getState$activeN = (_key$getState2 = key.getState(editorState)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.activeNode) !== null && _key$getState$activeN !== void 0 ? _key$getState$activeN : undefined,
62
101
  isDragging: (_key$getState$isDragg = (_key$getState3 = key.getState(editorState)) === null || _key$getState3 === void 0 ? void 0 : _key$getState3.isDragging) !== null && _key$getState$isDragg !== void 0 ? _key$getState$isDragg : false,
63
- isPMDragging: (_key$getState$isPMDra = (_key$getState4 = key.getState(editorState)) === null || _key$getState4 === void 0 ? void 0 : _key$getState4.isPMDragging) !== null && _key$getState$isPMDra !== void 0 ? _key$getState$isPMDra : false
102
+ isPMDragging: (_key$getState$isPMDra = (_key$getState4 = key.getState(editorState)) === null || _key$getState4 === void 0 ? void 0 : _key$getState4.isPMDragging) !== null && _key$getState$isPMDra !== void 0 ? _key$getState$isPMDra : false,
103
+ multiSelectDnD: (_key$getState$multiSe = (_key$getState5 = key.getState(editorState)) === null || _key$getState5 === void 0 ? void 0 : _key$getState5.multiSelectDnD) !== null && _key$getState$multiSe !== void 0 ? _key$getState$multiSe : undefined
64
104
  };
65
105
  },
66
106
  contentComponent() {
@@ -16,6 +16,7 @@ import { attachMoveNodeAnalytics } from '../pm-plugins/utils/fire-analytics';
16
16
  import { getNestedNodePosition } from '../pm-plugins/utils/getNestedNodePosition';
17
17
  import { selectNode, setCursorPositionAtMovedNode } from '../pm-plugins/utils/getSelection';
18
18
  import { removeFromSource } from '../pm-plugins/utils/remove-from-source';
19
+ import { getMultiSelectionIfPosInside } from '../pm-plugins/utils/selection';
19
20
  import { canMoveNodeToIndex, isInsideTable, transformSliceExpandToNestedExpand } from '../pm-plugins/utils/validation';
20
21
 
21
22
  /**
@@ -134,7 +135,8 @@ export const moveNodeViaShortcut = (api, direction, formatMessage) => {
134
135
 
135
136
  // if the current node is the last node, don't do anything
136
137
  if (index >= parent.childCount - 1) {
137
- return false;
138
+ // prevent event propagation to avoid moving the cursor and still select the node
139
+ return true;
138
140
  }
139
141
  const moveToEnd = index === parent.childCount - 2;
140
142
  moveToPos = moveToEnd ? $pos.before() : selection.to + ((nextNode === null || nextNode === void 0 ? void 0 : nextNode.nodeSize) || 1);
@@ -217,26 +219,29 @@ export const moveNodeViaShortcut = (api, direction, formatMessage) => {
217
219
  export const moveNode = api => (start, to, inputMethod = INPUT_METHOD.DRAG_AND_DROP, formatMessage) => ({
218
220
  tr
219
221
  }) => {
220
- const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
221
- exposure: true
222
- });
223
- const selection = tr.selection;
224
- const selectionFrom = selection.$from.pos;
225
- const selectionTo = selection.$to.pos;
222
+ if (!api) {
223
+ return tr;
224
+ }
226
225
  const handleNode = tr.doc.nodeAt(start);
227
226
  if (!handleNode) {
228
227
  return tr;
229
228
  }
230
229
  let sliceFrom = start;
231
230
  let sliceTo;
231
+ const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
232
+ exposure: true
233
+ });
232
234
  if (isMultiSelect) {
233
235
  var _handleNode$nodeSize;
234
- // //If the handle position sits within the Editor selection, we will move all nodes that sit in that selection
235
- const useSelection = sliceFrom >= selectionFrom - 1 && sliceFrom <= selectionTo;
236
- sliceFrom = useSelection ? selectionFrom : start;
236
+ const {
237
+ anchor,
238
+ head
239
+ } = getMultiSelectionIfPosInside(api, start);
240
+ const inSelection = anchor !== undefined && head !== undefined;
241
+ sliceFrom = inSelection ? Math.min(anchor, head) : start;
237
242
  const handleSize = (_handleNode$nodeSize = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize !== void 0 ? _handleNode$nodeSize : 1;
238
243
  const handleEnd = sliceFrom + handleSize;
239
- sliceTo = useSelection ? selectionTo : handleEnd;
244
+ sliceTo = inSelection ? Math.max(anchor, head) : handleEnd;
240
245
  } else {
241
246
  var _handleNode$nodeSize2;
242
247
  const size = (_handleNode$nodeSize2 = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize2 !== void 0 ? _handleNode$nodeSize2 : 1;