@atlaskit/editor-plugin-block-controls 2.19.1 → 2.20.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,25 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 2.20.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#102564](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/102564)
8
+ [`078168e470e88`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/078168e470e88) -
9
+ [ux] Add initial multi-select
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+
15
+ ## 2.19.2
16
+
17
+ ### Patch Changes
18
+
19
+ - [#102237](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/102237)
20
+ [`ff4d14b55fec9`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/ff4d14b55fec9) -
21
+ [ED-26244] clean up platform_editor_element_drag_and_drop_ed_24885
22
+
3
23
  ## 2.19.1
4
24
 
5
25
  ### Patch Changes
@@ -6,11 +6,9 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.blockControlsPlugin = void 0;
8
8
  var _react = _interopRequireDefault(require("react"));
9
- var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
10
9
  var _moveNode = require("./editor-commands/move-node");
11
10
  var _moveToLayout = require("./editor-commands/move-to-layout");
12
11
  var _main = require("./pm-plugins/main");
13
- var _getSelection = require("./pm-plugins/utils/getSelection");
14
12
  var _dragHandleMenu = require("./ui/drag-handle-menu");
15
13
  var _globalStyles = require("./ui/global-styles");
16
14
  var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPlugin(_ref) {
@@ -53,9 +51,6 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
53
51
  if (pos === undefined) {
54
52
  return tr;
55
53
  }
56
- if (!(0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_24885')) {
57
- tr = (0, _getSelection.selectNode)(tr, pos, nodeType);
58
- }
59
54
  tr.setMeta(_main.key, {
60
55
  isDragging: true,
61
56
  activeNode: {
@@ -165,37 +165,55 @@ var moveNode = exports.moveNode = function moveNode(api) {
165
165
  // eslint-disable-next-line @typescript-eslint/max-params
166
166
  = arguments.length > 3 ? arguments[3] : undefined;
167
167
  return function (_ref4) {
168
- var _node$nodeSize;
169
168
  var tr = _ref4.tr;
170
- var node = tr.doc.nodeAt(start);
171
- var resolvedNode = tr.doc.resolve(start);
172
- if (!node) {
169
+ var isMultiSelect = (0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true, {
170
+ exposure: true
171
+ });
172
+ var selection = tr.selection;
173
+ var selectionFrom = selection.$from.pos;
174
+ var selectionTo = selection.$to.pos;
175
+ var handleNode = tr.doc.nodeAt(start);
176
+ if (!handleNode) {
173
177
  return tr;
174
178
  }
179
+ var sliceFrom = start;
180
+ var sliceTo;
181
+ if (isMultiSelect) {
182
+ var _handleNode$nodeSize;
183
+ // //If the handle position sits within the Editor selection, we will move all nodes that sit in that selection
184
+ var useSelection = sliceFrom >= selectionFrom - 1 && sliceFrom <= selectionTo;
185
+ sliceFrom = useSelection ? selectionFrom : start;
186
+ var handleSize = (_handleNode$nodeSize = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize !== void 0 ? _handleNode$nodeSize : 1;
187
+ var handleEnd = sliceFrom + handleSize;
188
+ sliceTo = useSelection ? selectionTo : handleEnd;
189
+ } else {
190
+ var _handleNode$nodeSize2;
191
+ var size = (_handleNode$nodeSize2 = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize2 !== void 0 ? _handleNode$nodeSize2 : 1;
192
+ sliceTo = sliceFrom + size;
193
+ }
175
194
  var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
176
195
  expand = _tr$doc$type$schema$n.expand,
177
196
  nestedExpand = _tr$doc$type$schema$n.nestedExpand;
178
- var size = (_node$nodeSize = node === null || node === void 0 ? void 0 : node.nodeSize) !== null && _node$nodeSize !== void 0 ? _node$nodeSize : 1;
179
- var end = start + size;
180
- var $from = tr.doc.resolve(start);
181
197
  var $to = tr.doc.resolve(to);
198
+ var $handlePos = tr.doc.resolve(start);
182
199
  var mappedTo;
183
200
  if ((0, _experiments.editorExperiment)('nested-dnd', true)) {
184
- var nodeCopy = tr.doc.slice(start, end, false); // cut the content
201
+ var nodeCopy = tr.doc.slice(sliceFrom, sliceTo, false); // cut the content
185
202
  var destType = $to.node().type;
186
203
  var destParent = $to.node($to.depth);
187
- var sourceNode = $from.nodeAfter;
204
+ var sourceNode = $handlePos.nodeAfter;
188
205
 
206
+ //TODO: Does this need to be updated with new selection logic above? ^
189
207
  // Move a layout column to top level
190
- if (sourceNode && isDragLayoutColumnToTopLevel($from, $to)) {
208
+ if (sourceNode && isDragLayoutColumnToTopLevel($handlePos, $to)) {
191
209
  // need update after we support single column layout.
192
210
  var fragment = _model.Fragment.from(sourceNode.content);
193
- (0, _removeFromSource.removeFromSource)(tr, $from);
211
+ (0, _removeFromSource.removeFromSource)(tr, $handlePos);
194
212
  var _mappedTo = tr.mapping.map(to);
195
213
  tr.insert(_mappedTo, fragment).setSelection(_state.Selection.near(tr.doc.resolve(_mappedTo))).scrollIntoView();
196
214
  return tr;
197
215
  }
198
- if (!(0, _validation.canMoveNodeToIndex)(destParent, $to.index(), $from.node().child($from.index()), $to)) {
216
+ if (!(0, _validation.canMoveNodeToIndex)(destParent, $to.index(), $handlePos.node().child($handlePos.index()), $to)) {
199
217
  return tr;
200
218
  }
201
219
  var convertedNodeSlice = transformSourceSlice(nodeCopy, destType);
@@ -203,7 +221,7 @@ var moveNode = exports.moveNode = function moveNode(api) {
203
221
  if (!convertedNode) {
204
222
  return tr;
205
223
  }
206
- tr.delete(start, end); // delete the content from the original position
224
+ tr.delete(sliceFrom, sliceTo); // delete the content from the original position
207
225
  mappedTo = tr.mapping.map(to);
208
226
  var isDestNestedLoneEmptyParagraph = destParent.type.name !== 'doc' && destParent.childCount === 1 && (0, _utils.isEmptyParagraph)($to.nodeAfter);
209
227
  if (convertedNodeSlice && isDestNestedLoneEmptyParagraph) {
@@ -214,12 +232,12 @@ var moveNode = exports.moveNode = function moveNode(api) {
214
232
  tr.insert(mappedTo, convertedNode);
215
233
  }
216
234
  } else {
217
- var _nodeCopy = tr.doc.content.cut(start, end); // cut the content
218
- tr.delete(start, end); // delete the content from the original position
235
+ var _nodeCopy = tr.doc.content.cut(sliceFrom, sliceTo); // cut the content
236
+ tr.delete(sliceFrom, sliceTo); // delete the content from the original position
219
237
  mappedTo = tr.mapping.map(to);
220
238
  tr.insert(mappedTo, _nodeCopy); // insert the content at the new position
221
239
  }
222
- tr = inputMethod === _analytics.INPUT_METHOD.DRAG_AND_DROP ? (0, _getSelection.setCursorPositionAtMovedNode)(tr, mappedTo) : (0, _getSelection.selectNode)(tr, mappedTo, node.type.name);
240
+ tr = inputMethod === _analytics.INPUT_METHOD.DRAG_AND_DROP ? (0, _getSelection.setCursorPositionAtMovedNode)(tr, mappedTo) : (0, _getSelection.selectNode)(tr, mappedTo, handleNode.type.name);
223
241
  tr.setMeta(_main.key, {
224
242
  nodeMoved: true
225
243
  });
@@ -234,7 +252,7 @@ var moveNode = exports.moveNode = function moveNode(api) {
234
252
  }
235
253
  }
236
254
  if ((0, _experiments.editorExperiment)('advanced_layouts', true)) {
237
- (0, _fireAnalytics.attachMoveNodeAnalytics)(tr, inputMethod, resolvedNode.depth, node.type.name, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.depth, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.parent.type.name, $from.sameParent($mappedTo), api);
255
+ (0, _fireAnalytics.attachMoveNodeAnalytics)(tr, inputMethod, $handlePos.depth, handleNode.type.name, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.depth, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.parent.type.name, $handlePos.sameParent($mappedTo), api);
238
256
  } else {
239
257
  var _api$analytics;
240
258
  api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
@@ -243,8 +261,8 @@ var moveNode = exports.moveNode = function moveNode(api) {
243
261
  actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
244
262
  actionSubjectId: _analytics.ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
245
263
  attributes: _objectSpread({
246
- nodeDepth: resolvedNode.depth,
247
- nodeType: node.type.name,
264
+ nodeDepth: $handlePos.depth,
265
+ nodeType: handleNode.type.name,
248
266
  destinationNodeDepth: $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.depth,
249
267
  destinationNodeType: $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.parent.type.name
250
268
  }, (0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_23873') && {
@@ -254,7 +272,7 @@ var moveNode = exports.moveNode = function moveNode(api) {
254
272
  }
255
273
  if ((0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_23873')) {
256
274
  var _api$accessibilityUti;
257
- var movedMessage = to > start ? _messages.blockControlsMessages.movedDown : _messages.blockControlsMessages.movedup;
275
+ var movedMessage = to > sliceFrom ? _messages.blockControlsMessages.movedDown : _messages.blockControlsMessages.movedup;
258
276
  api === null || api === void 0 || (_api$accessibilityUti = api.accessibilityUtils) === null || _api$accessibilityUti === void 0 || _api$accessibilityUti.actions.ariaNotify(formatMessage ? formatMessage(movedMessage) : movedMessage.defaultMessage, {
259
277
  priority: 'important'
260
278
  });
@@ -73,7 +73,7 @@ var selectedStyles = (0, _react2.css)({
73
73
  color: "var(--ds-icon-selected, #0C66E4)"
74
74
  });
75
75
  var DragHandle = exports.DragHandle = function DragHandle(_ref) {
76
- var _api$core2, _api$analytics2, _api$core4, _api$core6;
76
+ var _api$core2, _api$analytics2, _api$core4;
77
77
  var view = _ref.view,
78
78
  api = _ref.api,
79
79
  formatMessage = _ref.formatMessage,
@@ -146,7 +146,6 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
146
146
  // as expected with a node selection. This workaround sets the selection to the node on mouseDown,
147
147
  // but ensures the preview is generated correctly.
148
148
  var handleMouseDown = (0, _react.useCallback)(function () {
149
- var _api$core3;
150
149
  if ((0, _experiments.editorExperiment)('advanced_layouts', true)) {
151
150
  // prevent native drag and drop.
152
151
  if ((0, _platformFeatureFlags.fg)('platform_editor_advanced_layouts_post_fix_patch_1')) {
@@ -157,39 +156,16 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
157
156
  return undefined;
158
157
  }
159
158
  }
160
- if ((0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_24885')) {
161
- return undefined;
162
- }
163
- api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref3) {
164
- var tr = _ref3.tr;
165
- var startPos = getPos();
166
- if (startPos === undefined) {
167
- return tr;
168
- }
169
- var node = tr.doc.nodeAt(startPos);
170
- if (!node) {
171
- return tr;
172
- }
173
- var selection;
174
- if (isLayoutColumn && (0, _experiments.editorExperiment)('advanced_layouts', true)) {
175
- selection = new _state.NodeSelection(tr.doc.resolve(startPos));
176
- } else {
177
- var $startPos = tr.doc.resolve(startPos + node.nodeSize);
178
- selection = new _state.TextSelection($startPos);
179
- }
180
- tr.setSelection(selection);
181
- return tr;
182
- });
183
- }, [api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, getPos, isLayoutColumn]);
159
+ }, [isLayoutColumn]);
184
160
  var handleKeyDown = (0, _react.useCallback)(function (e) {
185
161
  if ((0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_23873')) {
186
162
  // allow user to use spacebar to select the node
187
163
 
188
164
  if (!e.repeat && e.key === ' ') {
189
- var _api$core5;
165
+ var _api$core3;
190
166
  var startPos = getPos();
191
- api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref4) {
192
- var tr = _ref4.tr;
167
+ api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref3) {
168
+ var tr = _ref3.tr;
193
169
  if (startPos === undefined) {
194
170
  return tr;
195
171
  }
@@ -213,7 +189,7 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
213
189
  view.focus();
214
190
  }
215
191
  }
216
- }, [getPos, api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 ? void 0 : _api$core6.actions, view]);
192
+ }, [getPos, api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, view]);
217
193
  (0, _react.useEffect)(function () {
218
194
  var element = buttonRef.current;
219
195
  if (!element) {
@@ -227,11 +203,11 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
227
203
  start: start
228
204
  };
229
205
  },
230
- onGenerateDragPreview: function onGenerateDragPreview(_ref5) {
231
- var nativeSetDragImage = _ref5.nativeSetDragImage;
206
+ onGenerateDragPreview: function onGenerateDragPreview(_ref4) {
207
+ var nativeSetDragImage = _ref4.nativeSetDragImage;
232
208
  (0, _setCustomNativeDragPreview.setCustomNativeDragPreview)({
233
- render: function render(_ref6) {
234
- var container = _ref6.container;
209
+ render: function render(_ref5) {
210
+ var container = _ref5.container;
235
211
  var dom = view.dom.querySelector("[data-drag-handler-anchor-name=\"".concat(anchorName, "\"]"));
236
212
  if (!dom) {
237
213
  return;
@@ -242,17 +218,44 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
242
218
  });
243
219
  },
244
220
  onDragStart: function onDragStart() {
245
- var _api$core7;
221
+ var _api$core5;
246
222
  if (start === undefined) {
247
223
  return;
248
224
  }
249
- api === null || api === void 0 || (_api$core7 = api.core) === null || _api$core7 === void 0 || _api$core7.actions.execute(function (_ref7) {
225
+ api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref6) {
250
226
  var _api$blockControls, _api$analytics3;
251
- var tr = _ref7.tr;
227
+ var tr = _ref6.tr;
228
+ var isMultiSelect = (0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true, {
229
+ exposure: true
230
+ });
231
+ var selectionStart = start;
232
+ if (isMultiSelect) {
233
+ var selection = tr.selection;
234
+ var selectionFrom = selection.$from.pos;
235
+ var selectionTo = selection.$to.pos;
236
+ var $selectionFrom = tr.doc.resolve(selectionFrom);
237
+ var $selectionTo = tr.doc.resolve(selectionTo);
238
+ selectionStart = $selectionFrom.start();
239
+ var selectionEnd = $selectionTo.end();
240
+ var handlePos = getPos();
241
+ if (typeof handlePos !== 'number') {
242
+ return tr;
243
+ }
244
+ var posBeforeNode = $selectionFrom.pos ? $selectionFrom.start() - 1 : $selectionFrom.pos;
245
+ var shouldExpandSelection = handlePos >= posBeforeNode && handlePos <= selectionEnd;
246
+ if (shouldExpandSelection) {
247
+ //TODO: What happens if not a text selection?
248
+ var newSelection = _state.TextSelection.create(tr.doc, selectionStart, selectionEnd);
249
+ tr.setSelection(newSelection);
250
+ } else {
251
+ var _$selectionFrom = tr.doc.resolve(handlePos + 1);
252
+ (0, _getSelection.selectNode)(tr, handlePos, _$selectionFrom.node().type.name);
253
+ }
254
+ }
252
255
  api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.setNodeDragged(getPos, anchorName, nodeType)({
253
256
  tr: tr
254
257
  });
255
- var resolvedMovingNode = tr.doc.resolve(start);
258
+ var resolvedMovingNode = tr.doc.resolve(selectionStart);
256
259
  var maybeNode = resolvedMovingNode.nodeAfter;
257
260
  tr.setMeta('scrollIntoView', false);
258
261
  api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.attachAnalyticsEvent({
@@ -1,9 +1,7 @@
1
1
  import React from 'react';
2
- import { fg } from '@atlaskit/platform-feature-flags';
3
2
  import { moveNode } from './editor-commands/move-node';
4
3
  import { moveToLayout } from './editor-commands/move-to-layout';
5
4
  import { createPlugin, key } from './pm-plugins/main';
6
- import { selectNode } from './pm-plugins/utils/getSelection';
7
5
  import { DragHandleMenu } from './ui/drag-handle-menu';
8
6
  import { GlobalStylesWrapper } from './ui/global-styles';
9
7
  export const blockControlsPlugin = ({
@@ -44,9 +42,6 @@ export const blockControlsPlugin = ({
44
42
  if (pos === undefined) {
45
43
  return tr;
46
44
  }
47
- if (!fg('platform_editor_element_drag_and_drop_ed_24885')) {
48
- tr = selectNode(tr, pos, nodeType);
49
- }
50
45
  tr.setMeta(key, {
51
46
  isDragging: true,
52
47
  activeNode: {
@@ -160,37 +160,55 @@ export const moveNode = api => (start, to, inputMethod = INPUT_METHOD.DRAG_AND_D
160
160
  ) => ({
161
161
  tr
162
162
  }) => {
163
- var _node$nodeSize;
164
- const node = tr.doc.nodeAt(start);
165
- const resolvedNode = tr.doc.resolve(start);
166
- if (!node) {
163
+ const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
164
+ exposure: true
165
+ });
166
+ const selection = tr.selection;
167
+ const selectionFrom = selection.$from.pos;
168
+ const selectionTo = selection.$to.pos;
169
+ const handleNode = tr.doc.nodeAt(start);
170
+ if (!handleNode) {
167
171
  return tr;
168
172
  }
173
+ let sliceFrom = start;
174
+ let sliceTo;
175
+ if (isMultiSelect) {
176
+ var _handleNode$nodeSize;
177
+ // //If the handle position sits within the Editor selection, we will move all nodes that sit in that selection
178
+ const useSelection = sliceFrom >= selectionFrom - 1 && sliceFrom <= selectionTo;
179
+ sliceFrom = useSelection ? selectionFrom : start;
180
+ const handleSize = (_handleNode$nodeSize = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize !== void 0 ? _handleNode$nodeSize : 1;
181
+ const handleEnd = sliceFrom + handleSize;
182
+ sliceTo = useSelection ? selectionTo : handleEnd;
183
+ } else {
184
+ var _handleNode$nodeSize2;
185
+ const size = (_handleNode$nodeSize2 = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize2 !== void 0 ? _handleNode$nodeSize2 : 1;
186
+ sliceTo = sliceFrom + size;
187
+ }
169
188
  const {
170
189
  expand,
171
190
  nestedExpand
172
191
  } = tr.doc.type.schema.nodes;
173
- const size = (_node$nodeSize = node === null || node === void 0 ? void 0 : node.nodeSize) !== null && _node$nodeSize !== void 0 ? _node$nodeSize : 1;
174
- const end = start + size;
175
- const $from = tr.doc.resolve(start);
176
192
  const $to = tr.doc.resolve(to);
193
+ const $handlePos = tr.doc.resolve(start);
177
194
  let mappedTo;
178
195
  if (editorExperiment('nested-dnd', true)) {
179
- const nodeCopy = tr.doc.slice(start, end, false); // cut the content
196
+ const nodeCopy = tr.doc.slice(sliceFrom, sliceTo, false); // cut the content
180
197
  const destType = $to.node().type;
181
198
  const destParent = $to.node($to.depth);
182
- const sourceNode = $from.nodeAfter;
199
+ const sourceNode = $handlePos.nodeAfter;
183
200
 
201
+ //TODO: Does this need to be updated with new selection logic above? ^
184
202
  // Move a layout column to top level
185
- if (sourceNode && isDragLayoutColumnToTopLevel($from, $to)) {
203
+ if (sourceNode && isDragLayoutColumnToTopLevel($handlePos, $to)) {
186
204
  // need update after we support single column layout.
187
205
  const fragment = Fragment.from(sourceNode.content);
188
- removeFromSource(tr, $from);
206
+ removeFromSource(tr, $handlePos);
189
207
  const mappedTo = tr.mapping.map(to);
190
208
  tr.insert(mappedTo, fragment).setSelection(Selection.near(tr.doc.resolve(mappedTo))).scrollIntoView();
191
209
  return tr;
192
210
  }
193
- if (!canMoveNodeToIndex(destParent, $to.index(), $from.node().child($from.index()), $to)) {
211
+ if (!canMoveNodeToIndex(destParent, $to.index(), $handlePos.node().child($handlePos.index()), $to)) {
194
212
  return tr;
195
213
  }
196
214
  const convertedNodeSlice = transformSourceSlice(nodeCopy, destType);
@@ -198,7 +216,7 @@ export const moveNode = api => (start, to, inputMethod = INPUT_METHOD.DRAG_AND_D
198
216
  if (!convertedNode) {
199
217
  return tr;
200
218
  }
201
- tr.delete(start, end); // delete the content from the original position
219
+ tr.delete(sliceFrom, sliceTo); // delete the content from the original position
202
220
  mappedTo = tr.mapping.map(to);
203
221
  const isDestNestedLoneEmptyParagraph = destParent.type.name !== 'doc' && destParent.childCount === 1 && isEmptyParagraph($to.nodeAfter);
204
222
  if (convertedNodeSlice && isDestNestedLoneEmptyParagraph) {
@@ -209,12 +227,12 @@ export const moveNode = api => (start, to, inputMethod = INPUT_METHOD.DRAG_AND_D
209
227
  tr.insert(mappedTo, convertedNode);
210
228
  }
211
229
  } else {
212
- const nodeCopy = tr.doc.content.cut(start, end); // cut the content
213
- tr.delete(start, end); // delete the content from the original position
230
+ const nodeCopy = tr.doc.content.cut(sliceFrom, sliceTo); // cut the content
231
+ tr.delete(sliceFrom, sliceTo); // delete the content from the original position
214
232
  mappedTo = tr.mapping.map(to);
215
233
  tr.insert(mappedTo, nodeCopy); // insert the content at the new position
216
234
  }
217
- tr = inputMethod === INPUT_METHOD.DRAG_AND_DROP ? setCursorPositionAtMovedNode(tr, mappedTo) : selectNode(tr, mappedTo, node.type.name);
235
+ tr = inputMethod === INPUT_METHOD.DRAG_AND_DROP ? setCursorPositionAtMovedNode(tr, mappedTo) : selectNode(tr, mappedTo, handleNode.type.name);
218
236
  tr.setMeta(key, {
219
237
  nodeMoved: true
220
238
  });
@@ -229,7 +247,7 @@ export const moveNode = api => (start, to, inputMethod = INPUT_METHOD.DRAG_AND_D
229
247
  }
230
248
  }
231
249
  if (editorExperiment('advanced_layouts', true)) {
232
- attachMoveNodeAnalytics(tr, inputMethod, resolvedNode.depth, node.type.name, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.depth, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.parent.type.name, $from.sameParent($mappedTo), api);
250
+ attachMoveNodeAnalytics(tr, inputMethod, $handlePos.depth, handleNode.type.name, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.depth, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.parent.type.name, $handlePos.sameParent($mappedTo), api);
233
251
  } else {
234
252
  var _api$analytics;
235
253
  api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.attachAnalyticsEvent({
@@ -238,8 +256,8 @@ export const moveNode = api => (start, to, inputMethod = INPUT_METHOD.DRAG_AND_D
238
256
  actionSubject: ACTION_SUBJECT.ELEMENT,
239
257
  actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
240
258
  attributes: {
241
- nodeDepth: resolvedNode.depth,
242
- nodeType: node.type.name,
259
+ nodeDepth: $handlePos.depth,
260
+ nodeType: handleNode.type.name,
243
261
  destinationNodeDepth: $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.depth,
244
262
  destinationNodeType: $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.parent.type.name,
245
263
  ...(fg('platform_editor_element_drag_and_drop_ed_23873') && {
@@ -250,7 +268,7 @@ export const moveNode = api => (start, to, inputMethod = INPUT_METHOD.DRAG_AND_D
250
268
  }
251
269
  if (fg('platform_editor_element_drag_and_drop_ed_23873')) {
252
270
  var _api$accessibilityUti;
253
- const movedMessage = to > start ? blockControlsMessages.movedDown : blockControlsMessages.movedup;
271
+ const movedMessage = to > sliceFrom ? blockControlsMessages.movedDown : blockControlsMessages.movedup;
254
272
  api === null || api === void 0 ? void 0 : (_api$accessibilityUti = api.accessibilityUtils) === null || _api$accessibilityUti === void 0 ? void 0 : _api$accessibilityUti.actions.ariaNotify(formatMessage ? formatMessage(movedMessage) : movedMessage.defaultMessage, {
255
273
  priority: 'important'
256
274
  });
@@ -10,7 +10,7 @@ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit
10
10
  import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
11
11
  import { dragToMoveDown, dragToMoveLeft, dragToMoveRight, dragToMoveUp, getAriaKeyshortcuts, TooltipContentWithMultipleShortcuts } from '@atlaskit/editor-common/keymaps';
12
12
  import { blockControlsMessages } from '@atlaskit/editor-common/messages';
13
- import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
13
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
14
14
  import DragHandlerIcon from '@atlaskit/icon/glyph/drag-handler';
15
15
  import { fg } from '@atlaskit/platform-feature-flags';
16
16
  import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
@@ -71,7 +71,7 @@ export const DragHandle = ({
71
71
  handleOptions,
72
72
  isTopLevelNode = true
73
73
  }) => {
74
- var _api$core2, _api$analytics2, _api$core4, _api$core6;
74
+ var _api$core2, _api$analytics2, _api$core4;
75
75
  const start = getPos();
76
76
  const buttonRef = useRef(null);
77
77
  const [blockCardWidth, setBlockCardWidth] = useState(768);
@@ -129,7 +129,6 @@ export const DragHandle = ({
129
129
  // as expected with a node selection. This workaround sets the selection to the node on mouseDown,
130
130
  // but ensures the preview is generated correctly.
131
131
  const handleMouseDown = useCallback(() => {
132
- var _api$core3;
133
132
  if (editorExperiment('advanced_layouts', true)) {
134
133
  // prevent native drag and drop.
135
134
  if (fg('platform_editor_advanced_layouts_post_fix_patch_1')) {
@@ -140,39 +139,15 @@ export const DragHandle = ({
140
139
  return undefined;
141
140
  }
142
141
  }
143
- if (fg('platform_editor_element_drag_and_drop_ed_24885')) {
144
- return undefined;
145
- }
146
- api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(({
147
- tr
148
- }) => {
149
- const startPos = getPos();
150
- if (startPos === undefined) {
151
- return tr;
152
- }
153
- const node = tr.doc.nodeAt(startPos);
154
- if (!node) {
155
- return tr;
156
- }
157
- let selection;
158
- if (isLayoutColumn && editorExperiment('advanced_layouts', true)) {
159
- selection = new NodeSelection(tr.doc.resolve(startPos));
160
- } else {
161
- const $startPos = tr.doc.resolve(startPos + node.nodeSize);
162
- selection = new TextSelection($startPos);
163
- }
164
- tr.setSelection(selection);
165
- return tr;
166
- });
167
- }, [api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, getPos, isLayoutColumn]);
142
+ }, [isLayoutColumn]);
168
143
  const handleKeyDown = useCallback(e => {
169
144
  if (fg('platform_editor_element_drag_and_drop_ed_23873')) {
170
145
  // allow user to use spacebar to select the node
171
146
 
172
147
  if (!e.repeat && e.key === ' ') {
173
- var _api$core5;
148
+ var _api$core3;
174
149
  const startPos = getPos();
175
- api === null || api === void 0 ? void 0 : (_api$core5 = api.core) === null || _api$core5 === void 0 ? void 0 : _api$core5.actions.execute(({
150
+ api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(({
176
151
  tr
177
152
  }) => {
178
153
  if (startPos === undefined) {
@@ -196,7 +171,7 @@ export const DragHandle = ({
196
171
  view.focus();
197
172
  }
198
173
  }
199
- }, [getPos, api === null || api === void 0 ? void 0 : (_api$core6 = api.core) === null || _api$core6 === void 0 ? void 0 : _api$core6.actions, view]);
174
+ }, [getPos, api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, view]);
200
175
  useEffect(() => {
201
176
  const element = buttonRef.current;
202
177
  if (!element) {
@@ -225,18 +200,45 @@ export const DragHandle = ({
225
200
  });
226
201
  },
227
202
  onDragStart() {
228
- var _api$core7;
203
+ var _api$core5;
229
204
  if (start === undefined) {
230
205
  return;
231
206
  }
232
- api === null || api === void 0 ? void 0 : (_api$core7 = api.core) === null || _api$core7 === void 0 ? void 0 : _api$core7.actions.execute(({
207
+ api === null || api === void 0 ? void 0 : (_api$core5 = api.core) === null || _api$core5 === void 0 ? void 0 : _api$core5.actions.execute(({
233
208
  tr
234
209
  }) => {
235
210
  var _api$blockControls, _api$analytics3;
211
+ const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
212
+ exposure: true
213
+ });
214
+ let selectionStart = start;
215
+ if (isMultiSelect) {
216
+ const selection = tr.selection;
217
+ const selectionFrom = selection.$from.pos;
218
+ const selectionTo = selection.$to.pos;
219
+ const $selectionFrom = tr.doc.resolve(selectionFrom);
220
+ const $selectionTo = tr.doc.resolve(selectionTo);
221
+ selectionStart = $selectionFrom.start();
222
+ const selectionEnd = $selectionTo.end();
223
+ const handlePos = getPos();
224
+ if (typeof handlePos !== 'number') {
225
+ return tr;
226
+ }
227
+ const posBeforeNode = $selectionFrom.pos ? $selectionFrom.start() - 1 : $selectionFrom.pos;
228
+ const shouldExpandSelection = handlePos >= posBeforeNode && handlePos <= selectionEnd;
229
+ if (shouldExpandSelection) {
230
+ //TODO: What happens if not a text selection?
231
+ const newSelection = TextSelection.create(tr.doc, selectionStart, selectionEnd);
232
+ tr.setSelection(newSelection);
233
+ } else {
234
+ const $selectionFrom = tr.doc.resolve(handlePos + 1);
235
+ selectNode(tr, handlePos, $selectionFrom.node().type.name);
236
+ }
237
+ }
236
238
  api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.commands.setNodeDragged(getPos, anchorName, nodeType)({
237
239
  tr
238
240
  });
239
- const resolvedMovingNode = tr.doc.resolve(start);
241
+ const resolvedMovingNode = tr.doc.resolve(selectionStart);
240
242
  const maybeNode = resolvedMovingNode.nodeAfter;
241
243
  tr.setMeta('scrollIntoView', false);
242
244
  api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.attachAnalyticsEvent({
@@ -1,9 +1,7 @@
1
1
  import React from 'react';
2
- import { fg } from '@atlaskit/platform-feature-flags';
3
2
  import { moveNode } from './editor-commands/move-node';
4
3
  import { moveToLayout } from './editor-commands/move-to-layout';
5
4
  import { createPlugin, key } from './pm-plugins/main';
6
- import { selectNode } from './pm-plugins/utils/getSelection';
7
5
  import { DragHandleMenu } from './ui/drag-handle-menu';
8
6
  import { GlobalStylesWrapper } from './ui/global-styles';
9
7
  export var blockControlsPlugin = function blockControlsPlugin(_ref) {
@@ -46,9 +44,6 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
46
44
  if (pos === undefined) {
47
45
  return tr;
48
46
  }
49
- if (!fg('platform_editor_element_drag_and_drop_ed_24885')) {
50
- tr = selectNode(tr, pos, nodeType);
51
- }
52
47
  tr.setMeta(key, {
53
48
  isDragging: true,
54
49
  activeNode: {
@@ -159,37 +159,55 @@ export var moveNode = function moveNode(api) {
159
159
  // eslint-disable-next-line @typescript-eslint/max-params
160
160
  = arguments.length > 3 ? arguments[3] : undefined;
161
161
  return function (_ref4) {
162
- var _node$nodeSize;
163
162
  var tr = _ref4.tr;
164
- var node = tr.doc.nodeAt(start);
165
- var resolvedNode = tr.doc.resolve(start);
166
- if (!node) {
163
+ var isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
164
+ exposure: true
165
+ });
166
+ var selection = tr.selection;
167
+ var selectionFrom = selection.$from.pos;
168
+ var selectionTo = selection.$to.pos;
169
+ var handleNode = tr.doc.nodeAt(start);
170
+ if (!handleNode) {
167
171
  return tr;
168
172
  }
173
+ var sliceFrom = start;
174
+ var sliceTo;
175
+ if (isMultiSelect) {
176
+ var _handleNode$nodeSize;
177
+ // //If the handle position sits within the Editor selection, we will move all nodes that sit in that selection
178
+ var useSelection = sliceFrom >= selectionFrom - 1 && sliceFrom <= selectionTo;
179
+ sliceFrom = useSelection ? selectionFrom : start;
180
+ var handleSize = (_handleNode$nodeSize = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize !== void 0 ? _handleNode$nodeSize : 1;
181
+ var handleEnd = sliceFrom + handleSize;
182
+ sliceTo = useSelection ? selectionTo : handleEnd;
183
+ } else {
184
+ var _handleNode$nodeSize2;
185
+ var size = (_handleNode$nodeSize2 = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize2 !== void 0 ? _handleNode$nodeSize2 : 1;
186
+ sliceTo = sliceFrom + size;
187
+ }
169
188
  var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
170
189
  expand = _tr$doc$type$schema$n.expand,
171
190
  nestedExpand = _tr$doc$type$schema$n.nestedExpand;
172
- var size = (_node$nodeSize = node === null || node === void 0 ? void 0 : node.nodeSize) !== null && _node$nodeSize !== void 0 ? _node$nodeSize : 1;
173
- var end = start + size;
174
- var $from = tr.doc.resolve(start);
175
191
  var $to = tr.doc.resolve(to);
192
+ var $handlePos = tr.doc.resolve(start);
176
193
  var mappedTo;
177
194
  if (editorExperiment('nested-dnd', true)) {
178
- var nodeCopy = tr.doc.slice(start, end, false); // cut the content
195
+ var nodeCopy = tr.doc.slice(sliceFrom, sliceTo, false); // cut the content
179
196
  var destType = $to.node().type;
180
197
  var destParent = $to.node($to.depth);
181
- var sourceNode = $from.nodeAfter;
198
+ var sourceNode = $handlePos.nodeAfter;
182
199
 
200
+ //TODO: Does this need to be updated with new selection logic above? ^
183
201
  // Move a layout column to top level
184
- if (sourceNode && isDragLayoutColumnToTopLevel($from, $to)) {
202
+ if (sourceNode && isDragLayoutColumnToTopLevel($handlePos, $to)) {
185
203
  // need update after we support single column layout.
186
204
  var fragment = Fragment.from(sourceNode.content);
187
- removeFromSource(tr, $from);
205
+ removeFromSource(tr, $handlePos);
188
206
  var _mappedTo = tr.mapping.map(to);
189
207
  tr.insert(_mappedTo, fragment).setSelection(Selection.near(tr.doc.resolve(_mappedTo))).scrollIntoView();
190
208
  return tr;
191
209
  }
192
- if (!canMoveNodeToIndex(destParent, $to.index(), $from.node().child($from.index()), $to)) {
210
+ if (!canMoveNodeToIndex(destParent, $to.index(), $handlePos.node().child($handlePos.index()), $to)) {
193
211
  return tr;
194
212
  }
195
213
  var convertedNodeSlice = transformSourceSlice(nodeCopy, destType);
@@ -197,7 +215,7 @@ export var moveNode = function moveNode(api) {
197
215
  if (!convertedNode) {
198
216
  return tr;
199
217
  }
200
- tr.delete(start, end); // delete the content from the original position
218
+ tr.delete(sliceFrom, sliceTo); // delete the content from the original position
201
219
  mappedTo = tr.mapping.map(to);
202
220
  var isDestNestedLoneEmptyParagraph = destParent.type.name !== 'doc' && destParent.childCount === 1 && isEmptyParagraph($to.nodeAfter);
203
221
  if (convertedNodeSlice && isDestNestedLoneEmptyParagraph) {
@@ -208,12 +226,12 @@ export var moveNode = function moveNode(api) {
208
226
  tr.insert(mappedTo, convertedNode);
209
227
  }
210
228
  } else {
211
- var _nodeCopy = tr.doc.content.cut(start, end); // cut the content
212
- tr.delete(start, end); // delete the content from the original position
229
+ var _nodeCopy = tr.doc.content.cut(sliceFrom, sliceTo); // cut the content
230
+ tr.delete(sliceFrom, sliceTo); // delete the content from the original position
213
231
  mappedTo = tr.mapping.map(to);
214
232
  tr.insert(mappedTo, _nodeCopy); // insert the content at the new position
215
233
  }
216
- tr = inputMethod === INPUT_METHOD.DRAG_AND_DROP ? setCursorPositionAtMovedNode(tr, mappedTo) : selectNode(tr, mappedTo, node.type.name);
234
+ tr = inputMethod === INPUT_METHOD.DRAG_AND_DROP ? setCursorPositionAtMovedNode(tr, mappedTo) : selectNode(tr, mappedTo, handleNode.type.name);
217
235
  tr.setMeta(key, {
218
236
  nodeMoved: true
219
237
  });
@@ -228,7 +246,7 @@ export var moveNode = function moveNode(api) {
228
246
  }
229
247
  }
230
248
  if (editorExperiment('advanced_layouts', true)) {
231
- attachMoveNodeAnalytics(tr, inputMethod, resolvedNode.depth, node.type.name, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.depth, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.parent.type.name, $from.sameParent($mappedTo), api);
249
+ attachMoveNodeAnalytics(tr, inputMethod, $handlePos.depth, handleNode.type.name, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.depth, $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.parent.type.name, $handlePos.sameParent($mappedTo), api);
232
250
  } else {
233
251
  var _api$analytics;
234
252
  api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
@@ -237,8 +255,8 @@ export var moveNode = function moveNode(api) {
237
255
  actionSubject: ACTION_SUBJECT.ELEMENT,
238
256
  actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
239
257
  attributes: _objectSpread({
240
- nodeDepth: resolvedNode.depth,
241
- nodeType: node.type.name,
258
+ nodeDepth: $handlePos.depth,
259
+ nodeType: handleNode.type.name,
242
260
  destinationNodeDepth: $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.depth,
243
261
  destinationNodeType: $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.parent.type.name
244
262
  }, fg('platform_editor_element_drag_and_drop_ed_23873') && {
@@ -248,7 +266,7 @@ export var moveNode = function moveNode(api) {
248
266
  }
249
267
  if (fg('platform_editor_element_drag_and_drop_ed_23873')) {
250
268
  var _api$accessibilityUti;
251
- var movedMessage = to > start ? blockControlsMessages.movedDown : blockControlsMessages.movedup;
269
+ var movedMessage = to > sliceFrom ? blockControlsMessages.movedDown : blockControlsMessages.movedup;
252
270
  api === null || api === void 0 || (_api$accessibilityUti = api.accessibilityUtils) === null || _api$accessibilityUti === void 0 || _api$accessibilityUti.actions.ariaNotify(formatMessage ? formatMessage(movedMessage) : movedMessage.defaultMessage, {
253
271
  priority: 'important'
254
272
  });
@@ -12,7 +12,7 @@ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit
12
12
  import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
13
13
  import { dragToMoveDown, dragToMoveLeft, dragToMoveRight, dragToMoveUp, getAriaKeyshortcuts, TooltipContentWithMultipleShortcuts } from '@atlaskit/editor-common/keymaps';
14
14
  import { blockControlsMessages } from '@atlaskit/editor-common/messages';
15
- import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
15
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
16
16
  import DragHandlerIcon from '@atlaskit/icon/glyph/drag-handler';
17
17
  import { fg } from '@atlaskit/platform-feature-flags';
18
18
  import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
@@ -64,7 +64,7 @@ var selectedStyles = css({
64
64
  color: "var(--ds-icon-selected, #0C66E4)"
65
65
  });
66
66
  export var DragHandle = function DragHandle(_ref) {
67
- var _api$core2, _api$analytics2, _api$core4, _api$core6;
67
+ var _api$core2, _api$analytics2, _api$core4;
68
68
  var view = _ref.view,
69
69
  api = _ref.api,
70
70
  formatMessage = _ref.formatMessage,
@@ -137,7 +137,6 @@ export var DragHandle = function DragHandle(_ref) {
137
137
  // as expected with a node selection. This workaround sets the selection to the node on mouseDown,
138
138
  // but ensures the preview is generated correctly.
139
139
  var handleMouseDown = useCallback(function () {
140
- var _api$core3;
141
140
  if (editorExperiment('advanced_layouts', true)) {
142
141
  // prevent native drag and drop.
143
142
  if (fg('platform_editor_advanced_layouts_post_fix_patch_1')) {
@@ -148,39 +147,16 @@ export var DragHandle = function DragHandle(_ref) {
148
147
  return undefined;
149
148
  }
150
149
  }
151
- if (fg('platform_editor_element_drag_and_drop_ed_24885')) {
152
- return undefined;
153
- }
154
- api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref3) {
155
- var tr = _ref3.tr;
156
- var startPos = getPos();
157
- if (startPos === undefined) {
158
- return tr;
159
- }
160
- var node = tr.doc.nodeAt(startPos);
161
- if (!node) {
162
- return tr;
163
- }
164
- var selection;
165
- if (isLayoutColumn && editorExperiment('advanced_layouts', true)) {
166
- selection = new NodeSelection(tr.doc.resolve(startPos));
167
- } else {
168
- var $startPos = tr.doc.resolve(startPos + node.nodeSize);
169
- selection = new TextSelection($startPos);
170
- }
171
- tr.setSelection(selection);
172
- return tr;
173
- });
174
- }, [api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, getPos, isLayoutColumn]);
150
+ }, [isLayoutColumn]);
175
151
  var handleKeyDown = useCallback(function (e) {
176
152
  if (fg('platform_editor_element_drag_and_drop_ed_23873')) {
177
153
  // allow user to use spacebar to select the node
178
154
 
179
155
  if (!e.repeat && e.key === ' ') {
180
- var _api$core5;
156
+ var _api$core3;
181
157
  var startPos = getPos();
182
- api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref4) {
183
- var tr = _ref4.tr;
158
+ api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref3) {
159
+ var tr = _ref3.tr;
184
160
  if (startPos === undefined) {
185
161
  return tr;
186
162
  }
@@ -204,7 +180,7 @@ export var DragHandle = function DragHandle(_ref) {
204
180
  view.focus();
205
181
  }
206
182
  }
207
- }, [getPos, api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 ? void 0 : _api$core6.actions, view]);
183
+ }, [getPos, api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, view]);
208
184
  useEffect(function () {
209
185
  var element = buttonRef.current;
210
186
  if (!element) {
@@ -218,11 +194,11 @@ export var DragHandle = function DragHandle(_ref) {
218
194
  start: start
219
195
  };
220
196
  },
221
- onGenerateDragPreview: function onGenerateDragPreview(_ref5) {
222
- var nativeSetDragImage = _ref5.nativeSetDragImage;
197
+ onGenerateDragPreview: function onGenerateDragPreview(_ref4) {
198
+ var nativeSetDragImage = _ref4.nativeSetDragImage;
223
199
  setCustomNativeDragPreview({
224
- render: function render(_ref6) {
225
- var container = _ref6.container;
200
+ render: function render(_ref5) {
201
+ var container = _ref5.container;
226
202
  var dom = view.dom.querySelector("[data-drag-handler-anchor-name=\"".concat(anchorName, "\"]"));
227
203
  if (!dom) {
228
204
  return;
@@ -233,17 +209,44 @@ export var DragHandle = function DragHandle(_ref) {
233
209
  });
234
210
  },
235
211
  onDragStart: function onDragStart() {
236
- var _api$core7;
212
+ var _api$core5;
237
213
  if (start === undefined) {
238
214
  return;
239
215
  }
240
- api === null || api === void 0 || (_api$core7 = api.core) === null || _api$core7 === void 0 || _api$core7.actions.execute(function (_ref7) {
216
+ api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref6) {
241
217
  var _api$blockControls, _api$analytics3;
242
- var tr = _ref7.tr;
218
+ var tr = _ref6.tr;
219
+ var isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
220
+ exposure: true
221
+ });
222
+ var selectionStart = start;
223
+ if (isMultiSelect) {
224
+ var selection = tr.selection;
225
+ var selectionFrom = selection.$from.pos;
226
+ var selectionTo = selection.$to.pos;
227
+ var $selectionFrom = tr.doc.resolve(selectionFrom);
228
+ var $selectionTo = tr.doc.resolve(selectionTo);
229
+ selectionStart = $selectionFrom.start();
230
+ var selectionEnd = $selectionTo.end();
231
+ var handlePos = getPos();
232
+ if (typeof handlePos !== 'number') {
233
+ return tr;
234
+ }
235
+ var posBeforeNode = $selectionFrom.pos ? $selectionFrom.start() - 1 : $selectionFrom.pos;
236
+ var shouldExpandSelection = handlePos >= posBeforeNode && handlePos <= selectionEnd;
237
+ if (shouldExpandSelection) {
238
+ //TODO: What happens if not a text selection?
239
+ var newSelection = TextSelection.create(tr.doc, selectionStart, selectionEnd);
240
+ tr.setSelection(newSelection);
241
+ } else {
242
+ var _$selectionFrom = tr.doc.resolve(handlePos + 1);
243
+ selectNode(tr, handlePos, _$selectionFrom.node().type.name);
244
+ }
245
+ }
243
246
  api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.setNodeDragged(getPos, anchorName, nodeType)({
244
247
  tr: tr
245
248
  });
246
- var resolvedMovingNode = tr.doc.resolve(start);
249
+ var resolvedMovingNode = tr.doc.resolve(selectionStart);
247
250
  var maybeNode = resolvedMovingNode.nodeAfter;
248
251
  tr.setMeta('scrollIntoView', false);
249
252
  api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.attachAnalyticsEvent({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-controls",
3
- "version": "2.19.1",
3
+ "version": "2.20.0",
4
4
  "description": "Block controls plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -48,7 +48,7 @@
48
48
  "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^1.1.0",
49
49
  "@atlaskit/primitives": "^13.3.0",
50
50
  "@atlaskit/theme": "^14.0.0",
51
- "@atlaskit/tmp-editor-statsig": "^2.34.0",
51
+ "@atlaskit/tmp-editor-statsig": "^2.35.0",
52
52
  "@atlaskit/tokens": "^3.0.0",
53
53
  "@atlaskit/tooltip": "^19.0.0",
54
54
  "@babel/runtime": "^7.0.0",
@@ -118,9 +118,6 @@
118
118
  "platform_editor_element_drag_and_drop_debug": {
119
119
  "type": "boolean"
120
120
  },
121
- "platform_editor_element_drag_and_drop_ed_24885": {
122
- "type": "boolean"
123
- },
124
121
  "platform_editor_element_dnd_nested_fix_patch_6": {
125
122
  "type": "boolean"
126
123
  },