@atlaskit/editor-plugin-block-controls 11.2.10 → 11.2.11

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 (32) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cjs/editor-commands/move-node.js +12 -32
  3. package/dist/cjs/editor-commands/move-to-layout.js +59 -127
  4. package/dist/cjs/pm-plugins/decorations-drop-target-active.js +11 -16
  5. package/dist/cjs/pm-plugins/decorations-drop-target.js +13 -24
  6. package/dist/cjs/pm-plugins/main.js +51 -88
  7. package/dist/cjs/pm-plugins/utils/analytics.js +1 -2
  8. package/dist/cjs/pm-plugins/utils/remove-from-source.js +4 -14
  9. package/dist/cjs/ui/drag-handle.js +32 -44
  10. package/dist/es2019/editor-commands/move-node.js +9 -31
  11. package/dist/es2019/editor-commands/move-to-layout.js +61 -121
  12. package/dist/es2019/pm-plugins/decorations-drop-target-active.js +11 -16
  13. package/dist/es2019/pm-plugins/decorations-drop-target.js +13 -24
  14. package/dist/es2019/pm-plugins/main.js +55 -91
  15. package/dist/es2019/pm-plugins/utils/analytics.js +1 -2
  16. package/dist/es2019/pm-plugins/utils/remove-from-source.js +4 -14
  17. package/dist/es2019/ui/drag-handle.js +32 -45
  18. package/dist/esm/editor-commands/move-node.js +13 -33
  19. package/dist/esm/editor-commands/move-to-layout.js +59 -127
  20. package/dist/esm/pm-plugins/decorations-drop-target-active.js +11 -16
  21. package/dist/esm/pm-plugins/decorations-drop-target.js +13 -24
  22. package/dist/esm/pm-plugins/main.js +51 -88
  23. package/dist/esm/pm-plugins/utils/analytics.js +1 -2
  24. package/dist/esm/pm-plugins/utils/remove-from-source.js +4 -14
  25. package/dist/esm/ui/drag-handle.js +32 -44
  26. package/dist/types/pm-plugins/main.d.ts +0 -1
  27. package/dist/types/pm-plugins/utils/analytics.d.ts +2 -2
  28. package/dist/types/pm-plugins/utils/remove-from-source.d.ts +1 -1
  29. package/dist/types-ts4.5/pm-plugins/main.d.ts +0 -1
  30. package/dist/types-ts4.5/pm-plugins/utils/analytics.d.ts +2 -2
  31. package/dist/types-ts4.5/pm-plugins/utils/remove-from-source.d.ts +1 -1
  32. package/package.json +3 -3
@@ -41,26 +41,13 @@ const createNewLayout = (schema, layoutContents) => {
41
41
  };
42
42
  const moveToExistingLayout = (toLayout, toLayoutPos, sourceContent, from, to, tr, $originalFrom, $originalTo, api, selectMovedNode) => {
43
43
  const isSameLayout = isInSameLayout($originalFrom, $originalTo);
44
- let sourceContentEndPos = -1;
45
- const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true);
46
- let sourceNodeTypes, hasSelectedMultipleNodes;
47
- if (isMultiSelect) {
48
- if (sourceContent instanceof Fragment) {
49
- sourceContentEndPos = from + sourceContent.size;
50
- const attributes = getMultiSelectAnalyticsAttributes(tr, from, sourceContentEndPos);
51
- hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes;
52
- sourceNodeTypes = attributes.nodeTypes;
53
- }
54
- } else {
55
- if (sourceContent instanceof PMNode) {
56
- sourceContentEndPos = from + sourceContent.nodeSize;
57
- }
58
- }
59
- if (sourceContentEndPos === -1) {
60
- return tr;
61
- }
44
+ const sourceContentEndPos = from + sourceContent.size;
45
+ const attributes = getMultiSelectAnalyticsAttributes(tr, from, sourceContentEndPos);
46
+ const {
47
+ nodeTypes: sourceNodeTypes,
48
+ hasSelectedMultipleNodes
49
+ } = attributes;
62
50
  if (isSameLayout) {
63
- var _$originalFrom$nodeAf;
64
51
  // reorder columns
65
52
  tr.delete(from, sourceContentEndPos);
66
53
  const mappedTo = tr.mapping.map(to);
@@ -68,12 +55,11 @@ const moveToExistingLayout = (toLayout, toLayoutPos, sourceContent, from, to, tr
68
55
  if (selectMovedNode) {
69
56
  tr.setSelection(new NodeSelection(tr.doc.resolve(mappedTo))).scrollIntoView();
70
57
  }
71
- attachMoveNodeAnalytics(tr, INPUT_METHOD.DRAG_AND_DROP, $originalFrom.depth, ((_$originalFrom$nodeAf = $originalFrom.nodeAfter) === null || _$originalFrom$nodeAf === void 0 ? void 0 : _$originalFrom$nodeAf.type.name) || '', 1, 'layoutSection', true, api, sourceNodeTypes, hasSelectedMultipleNodes);
58
+ attachMoveNodeAnalytics(tr, INPUT_METHOD.DRAG_AND_DROP, $originalFrom.depth, sourceNodeTypes, 1, 'layoutSection', true, api, hasSelectedMultipleNodes);
72
59
  } else if (toLayout.childCount < maxLayoutColumnSupported()) {
73
- var _$originalFrom$nodeAf2;
74
60
  removeFromSource(tr, tr.doc.resolve(from), sourceContentEndPos);
75
61
  insertToDestinationNoWidthUpdate(tr, tr.mapping.map(to), sourceContent);
76
- attachMoveNodeAnalytics(tr, INPUT_METHOD.DRAG_AND_DROP, $originalFrom.depth, ((_$originalFrom$nodeAf2 = $originalFrom.nodeAfter) === null || _$originalFrom$nodeAf2 === void 0 ? void 0 : _$originalFrom$nodeAf2.type.name) || '', 1, 'layoutSection', false, api, sourceNodeTypes, hasSelectedMultipleNodes);
62
+ attachMoveNodeAnalytics(tr, INPUT_METHOD.DRAG_AND_DROP, $originalFrom.depth, sourceNodeTypes, 1, 'layoutSection', false, api, hasSelectedMultipleNodes);
77
63
  }
78
64
  return tr;
79
65
  };
@@ -92,22 +78,11 @@ const insertToDestinationNoWidthUpdate = (tr, to, sourceContent) => {
92
78
  } = tr.doc.type.schema.nodes || {};
93
79
  let content = null;
94
80
  try {
95
- if (editorExperiment('platform_editor_element_drag_and_drop_multiselect', true)) {
96
- if (sourceContent instanceof Fragment) {
97
- var _sourceFragment$first;
98
- const sourceFragment = sourceContent;
99
- content = layoutColumn.createChecked({
100
- width: 0
101
- }, isFragmentOfType(sourceFragment, 'layoutColumn') ? (_sourceFragment$first = sourceFragment.firstChild) === null || _sourceFragment$first === void 0 ? void 0 : _sourceFragment$first.content : sourceFragment);
102
- }
103
- } else {
104
- if (sourceContent instanceof PMNode) {
105
- const sourceNode = sourceContent;
106
- content = layoutColumn.createChecked({
107
- width: 0
108
- }, sourceNode.type.name === 'layoutColumn' ? sourceNode.content : sourceNode);
109
- }
110
- }
81
+ var _sourceFragment$first;
82
+ const sourceFragment = sourceContent;
83
+ content = layoutColumn.createChecked({
84
+ width: 0
85
+ }, isFragmentOfType(sourceFragment, 'layoutColumn') ? (_sourceFragment$first = sourceFragment.firstChild) === null || _sourceFragment$first === void 0 ? void 0 : _sourceFragment$first.content : sourceFragment);
111
86
  } catch (error) {
112
87
  logException(error, {
113
88
  location: 'editor-plugin-block-controls/move-to-layout'
@@ -151,7 +126,6 @@ const canMoveToLayout = (api, from, to, tr, moveNodeAtCursorPos) => {
151
126
  return;
152
127
  }
153
128
  const $from = tr.doc.resolve(from);
154
- const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true);
155
129
 
156
130
  // invalid from position or dragging a layout
157
131
  if (!$from.nodeAfter || $from.nodeAfter.type === layoutSection) {
@@ -160,7 +134,7 @@ const canMoveToLayout = (api, from, to, tr, moveNodeAtCursorPos) => {
160
134
  let sourceContent = $from.nodeAfter;
161
135
  let sourceFrom = from;
162
136
  let sourceTo = from + sourceContent.nodeSize;
163
- if (isMultiSelect && !moveNodeAtCursorPos) {
137
+ if (!moveNodeAtCursorPos) {
164
138
  const {
165
139
  anchor,
166
140
  head
@@ -188,62 +162,46 @@ const canMoveToLayout = (api, from, to, tr, moveNodeAtCursorPos) => {
188
162
  };
189
163
  };
190
164
  const removeBreakoutMarks = (tr, $from, to) => {
191
- let fromContentWithoutBreakout = $from.nodeAfter;
165
+ let fromContentWithoutBreakout = null;
192
166
  const {
193
167
  breakout
194
168
  } = tr.doc.type.schema.marks || {};
195
- if (editorExperiment('platform_editor_element_drag_and_drop_multiselect', true)) {
196
- tr.doc.nodesBetween($from.pos, to, (node, pos, parent) => {
197
- // should never remove breakout from previous layoutSection
198
- if (expValEquals('platform_editor_breakout_resizing', 'isEnabled', true)) {
199
- if (node.type.name === 'layoutSection') {
200
- return false;
201
- }
202
- }
203
-
204
- // breakout doesn't exist on nested nodes
205
- if ((parent === null || parent === void 0 ? void 0 : parent.type.name) === 'doc' && node.marks.some(m => m.type === breakout)) {
206
- tr.removeNodeMark(pos, breakout);
169
+ tr.doc.nodesBetween($from.pos, to, (node, pos, parent) => {
170
+ // should never remove breakout from previous layoutSection
171
+ if (expValEquals('platform_editor_breakout_resizing', 'isEnabled', true)) {
172
+ if (node.type.name === 'layoutSection') {
173
+ return false;
207
174
  }
175
+ }
208
176
 
209
- // descending is not needed as breakout doesn't exist on nested nodes
210
- return false;
211
- });
212
- // resolve again the source content after node updated (remove breakout marks)
213
- fromContentWithoutBreakout = tr.doc.slice($from.pos, to).content;
214
- } else {
215
- if (breakout && $from.nodeAfter && $from.nodeAfter.marks.some(m => m.type === breakout)) {
216
- tr.removeNodeMark($from.pos, breakout);
217
- // resolve again the source node after node updated (remove breakout marks)
218
- fromContentWithoutBreakout = tr.doc.resolve($from.pos).nodeAfter;
177
+ // breakout doesn't exist on nested nodes
178
+ if ((parent === null || parent === void 0 ? void 0 : parent.type.name) === 'doc' && node.marks.some(m => m.type === breakout)) {
179
+ tr.removeNodeMark(pos, breakout);
219
180
  }
220
- }
181
+
182
+ // descending is not needed as breakout doesn't exist on nested nodes
183
+ return false;
184
+ });
185
+ // resolve again the source content after node updated (remove breakout marks)
186
+ fromContentWithoutBreakout = tr.doc.slice($from.pos, to).content;
221
187
  return fromContentWithoutBreakout;
222
188
  };
223
189
  const getBreakoutMode = (content, breakout) => {
224
- if (editorExperiment('platform_editor_element_drag_and_drop_multiselect', true)) {
225
- if (content instanceof PMNode) {
226
- var _content$marks$find;
227
- return (_content$marks$find = content.marks.find(m => m.type === breakout)) === null || _content$marks$find === void 0 ? void 0 : _content$marks$find.attrs.mode;
228
- } else if (content instanceof Fragment) {
229
- // Find the first breakout mode in the fragment
230
- let firstBreakoutMode;
231
- for (let i = 0; i < content.childCount; i++) {
232
- const child = content.child(i);
233
- const breakoutMark = child.marks.find(m => m.type === breakout);
234
- if (breakoutMark) {
235
- firstBreakoutMode = breakoutMark.attrs.mode;
236
- break;
237
- }
190
+ if (content instanceof PMNode) {
191
+ var _content$marks$find;
192
+ return (_content$marks$find = content.marks.find(m => m.type === breakout)) === null || _content$marks$find === void 0 ? void 0 : _content$marks$find.attrs.mode;
193
+ } else if (content instanceof Fragment) {
194
+ // Find the first breakout mode in the fragment
195
+ let firstBreakoutMode;
196
+ for (let i = 0; i < content.childCount; i++) {
197
+ const child = content.child(i);
198
+ const breakoutMark = child.marks.find(m => m.type === breakout);
199
+ if (breakoutMark) {
200
+ firstBreakoutMode = breakoutMark.attrs.mode;
201
+ break;
238
202
  }
239
- return firstBreakoutMode;
240
- }
241
- } else {
242
- // Without multi-select support, we can assume source content is of type PMNode
243
- if (content instanceof PMNode) {
244
- var _content$marks$find2;
245
- return (_content$marks$find2 = content.marks.find(m => m.type === breakout)) === null || _content$marks$find2 === void 0 ? void 0 : _content$marks$find2.attrs.mode;
246
203
  }
204
+ return firstBreakoutMode;
247
205
  }
248
206
  };
249
207
  const getBreakoutModeAndWidth = (content, breakout) => {
@@ -252,30 +210,20 @@ const getBreakoutModeAndWidth = (content, breakout) => {
252
210
  breakoutMode: mark.attrs.mode,
253
211
  breakoutWidth: mark.attrs.width
254
212
  } : null;
255
- if (editorExperiment('platform_editor_element_drag_and_drop_multiselect', true)) {
256
- if (content instanceof PMNode) {
257
- return extractBreakoutAttributes(findBreakoutMark(content));
258
- } else if (content instanceof Fragment) {
259
- // Find the first breakout mode in the fragment
260
- for (let i = 0; i < content.childCount; i++) {
261
- const child = content.child(i);
262
- const breakoutMark = findBreakoutMark(child);
263
- if (breakoutMark) {
264
- return extractBreakoutAttributes(breakoutMark);
265
- }
213
+ if (content instanceof PMNode) {
214
+ return extractBreakoutAttributes(findBreakoutMark(content));
215
+ } else if (content instanceof Fragment) {
216
+ // Find the first breakout mode in the fragment
217
+ for (let i = 0; i < content.childCount; i++) {
218
+ const child = content.child(i);
219
+ const breakoutMark = findBreakoutMark(child);
220
+ if (breakoutMark) {
221
+ return extractBreakoutAttributes(breakoutMark);
266
222
  }
267
223
  }
268
- } else {
269
- // Without multi-select support, we can assume source content is of type PMNode
270
- if (content instanceof PMNode) {
271
- return extractBreakoutAttributes(findBreakoutMark(content));
272
- }
273
224
  }
274
225
  return null;
275
226
  };
276
-
277
- // TODO: ED-26959 - As part of platform_editor_element_drag_and_drop_multiselect clean up,
278
- // source content variable that has type of `PMNode | Fragment` should be updated to `Fragment` only
279
227
  export const moveToLayout = api => (from, to, options) => ({
280
228
  tr
281
229
  }) => {
@@ -315,8 +263,8 @@ export const moveToLayout = api => (from, to, options) => ({
315
263
  }
316
264
 
317
265
  // we don't want to remove marks when moving/re-ordering layoutSection
318
- const shouldRemoveMarks = !($sourceFrom.node().type === layoutSection && editorExperiment('platform_editor_element_drag_and_drop_multiselect', true));
319
- const fromContentBeforeBreakoutMarksRemoved = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true) ? tr.doc.slice($sourceFrom.pos, sourceTo).content : $sourceFrom.nodeAfter;
266
+ const shouldRemoveMarks = $sourceFrom.node().type !== layoutSection;
267
+ const fromContentBeforeBreakoutMarksRemoved = tr.doc.slice($sourceFrom.pos, sourceTo).content;
320
268
 
321
269
  // remove breakout from source content
322
270
  let fromContentWithoutBreakout = shouldRemoveMarks ? removeBreakoutMarks(tr, $sourceFrom, sourceTo) : fromContentBeforeBreakoutMarksRemoved;
@@ -329,7 +277,6 @@ export const moveToLayout = api => (from, to, options) => ({
329
277
  tr
330
278
  });
331
279
  }
332
- const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true);
333
280
  if (toNode.type === layoutSection) {
334
281
  const toPos = options !== null && options !== void 0 && options.moveToEnd ? to + toNode.nodeSize - 1 : to + 1;
335
282
  return moveToExistingLayout(toNode, to, fromContentWithoutBreakout, $sourceFrom.pos, toPos, tr, $sourceFrom, $to, api, options === null || options === void 0 ? void 0 : options.selectMovedNode);
@@ -347,24 +294,17 @@ export const moveToLayout = api => (from, to, options) => ({
347
294
  // resolve again the source node after node updated (remove breakout marks)
348
295
  toNodeWithoutBreakout = tr.doc.resolve(to).nodeAfter || toNode;
349
296
  }
350
- if (isMultiSelect) {
351
- if (isFragmentOfType(fromContentWithoutBreakout, 'layoutColumn') && fromContentWithoutBreakout.firstChild) {
352
- fromContentWithoutBreakout = fromContentWithoutBreakout.firstChild.content;
353
- }
354
- } else {
355
- if (fromContentWithoutBreakout instanceof PMNode && fromContentWithoutBreakout.type.name === 'layoutColumn') {
356
- fromContentWithoutBreakout = fromContentWithoutBreakout.content;
357
- }
297
+ if (isFragmentOfType(fromContentWithoutBreakout, 'layoutColumn') && fromContentWithoutBreakout.firstChild) {
298
+ fromContentWithoutBreakout = fromContentWithoutBreakout.firstChild.content;
358
299
  }
359
300
  const layoutContents = options !== null && options !== void 0 && options.moveToEnd ? [toNodeWithoutBreakout, fromContentWithoutBreakout] : [fromContentWithoutBreakout, toNodeWithoutBreakout];
360
301
  const newLayout = createNewLayout(tr.doc.type.schema, layoutContents);
361
302
  if (newLayout) {
362
- let sourceNodeTypes, hasSelectedMultipleNodes;
363
- if (isMultiSelect) {
364
- const attributes = getMultiSelectAnalyticsAttributes(tr, $sourceFrom.pos, sourceTo);
365
- hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes;
366
- sourceNodeTypes = attributes.nodeTypes;
367
- }
303
+ const attributes = getMultiSelectAnalyticsAttributes(tr, $sourceFrom.pos, sourceTo);
304
+ const {
305
+ nodeTypes: sourceNodeTypes,
306
+ hasSelectedMultipleNodes
307
+ } = attributes;
368
308
  tr = removeFromSource(tr, $sourceFrom, sourceTo);
369
309
  const mappedTo = tr.mapping.map(to);
370
310
  tr.delete(mappedTo, mappedTo + toNodeWithoutBreakout.nodeSize).insert(mappedTo, newLayout);
@@ -40,24 +40,19 @@ export const canMoveNodeOrSliceToPos = (state, node, parent, index, $toPos, acti
40
40
  const $activeNodePos = typeof activeNodePos === 'number' && state.doc.resolve(activeNodePos);
41
41
  const activePMNode = $activeNodePos && $activeNodePos.nodeAfter;
42
42
  const handleInsideSelection = activeNodePos !== undefined && activeNodePos >= selectionFrom && activeNodePos <= selectionTo;
43
- if (editorExperiment('platform_editor_element_drag_and_drop_multiselect', true)) {
44
- const selectionSlice = state.doc.slice(selectionFrom, selectionTo, false);
45
- const selectionSliceChildCount = selectionSlice.content.childCount;
46
- let canDropSingleNode = true;
47
- let canDropMultipleNodes = true;
43
+ const selectionSlice = state.doc.slice(selectionFrom, selectionTo, false);
44
+ const selectionSliceChildCount = selectionSlice.content.childCount;
45
+ let canDropSingleNode = true;
46
+ let canDropMultipleNodes = true;
48
47
 
49
- // when there is only one node in the slice, use the same logic as when multi select is not on
50
- if (selectionSliceChildCount > 1 && handleInsideSelection) {
51
- canDropMultipleNodes = canMoveSliceToIndex(selectionSlice, selectionFrom, selectionTo, parent, index, $toPos);
52
- } else {
53
- canDropSingleNode = !!(activePMNode && canMoveNodeToIndex(parent, index, activePMNode, $toPos, node));
54
- }
55
- if (!canDropMultipleNodes || !canDropSingleNode) {
56
- return false;
57
- }
48
+ // when there is only one node in the slice, use the same logic as when multi select is not on
49
+ if (selectionSliceChildCount > 1 && handleInsideSelection) {
50
+ canDropMultipleNodes = canMoveSliceToIndex(selectionSlice, selectionFrom, selectionTo, parent, index, $toPos);
58
51
  } else {
59
- const canDrop = activePMNode && canMoveNodeToIndex(parent, index, activePMNode, $toPos, node);
60
- return canDrop;
52
+ canDropSingleNode = !!(activePMNode && canMoveNodeToIndex(parent, index, activePMNode, $toPos, node));
53
+ }
54
+ if (!canDropMultipleNodes || !canDropSingleNode) {
55
+ return false;
61
56
  }
62
57
  return true;
63
58
  };
@@ -161,7 +161,6 @@ export const dropTargetDecorations = (newState, api, formatMessage, nodeViewPort
161
161
  const activeNodePos = activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos;
162
162
  const $activeNodePos = typeof activeNodePos === 'number' && newState.doc.resolve(activeNodePos);
163
163
  const activePMNode = $activeNodePos && $activeNodePos.nodeAfter;
164
- const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true);
165
164
  anchorRectCache === null || anchorRectCache === void 0 ? void 0 : anchorRectCache.clear();
166
165
  const prevNodeStack = [];
167
166
  const popNodeStack = depth => {
@@ -218,31 +217,21 @@ export const dropTargetDecorations = (newState, api, formatMessage, nodeViewPort
218
217
  return shouldDescend(node); //skip over, don't consider it a valid depth
219
218
  }
220
219
 
221
- // When multi select is on, validate all the nodes in the selection instead of just the handle node
222
- if (isMultiSelect) {
223
- const selectionSlice = newState.doc.slice(selectionFrom, selectionTo, false);
224
- const selectionSliceChildCount = selectionSlice.content.childCount;
225
- let canDropSingleNode = true;
226
- let canDropMultipleNodes = true;
220
+ // validate all the nodes in the selection instead of just the handle node
221
+ const selectionSlice = newState.doc.slice(selectionFrom, selectionTo, false);
222
+ const selectionSliceChildCount = selectionSlice.content.childCount;
223
+ let canDropSingleNode = true;
224
+ let canDropMultipleNodes = true;
227
225
 
228
- // when there is only one node in the slice, use the same logic as when multi select is not on
229
- if (selectionSliceChildCount > 1 && handleInsideSelection) {
230
- canDropMultipleNodes = canMoveSliceToIndex(selectionSlice, selectionFrom, selectionTo, parent, index, $pos);
231
- } else {
232
- canDropSingleNode = !!(activePMNode && canMoveNodeToIndex(parent, index, activePMNode, $pos, node));
233
- }
234
- if (!canDropMultipleNodes || !canDropSingleNode) {
235
- pushNodeStack(node, depth);
236
- return false; //not valid pos, so nested not valid either
237
- }
226
+ // when there is only one node in the slice, use the same logic as when multi select is not on
227
+ if (selectionSliceChildCount > 1 && handleInsideSelection) {
228
+ canDropMultipleNodes = canMoveSliceToIndex(selectionSlice, selectionFrom, selectionTo, parent, index, $pos);
238
229
  } else {
239
- const canDrop = activePMNode && canMoveNodeToIndex(parent, index, activePMNode, $pos, node);
240
-
241
- //NOTE: This will block drop targets showing for nodes that are valid after transformation (i.e. expand -> nestedExpand)
242
- if (!canDrop) {
243
- pushNodeStack(node, depth);
244
- return false; //not valid pos, so nested not valid either
245
- }
230
+ canDropSingleNode = !!(activePMNode && canMoveNodeToIndex(parent, index, activePMNode, $pos, node));
231
+ }
232
+ if (!canDropMultipleNodes || !canDropSingleNode) {
233
+ pushNodeStack(node, depth);
234
+ return false; //not valid pos, so nested not valid either
246
235
  }
247
236
  const parentTypesWithEndDropTarget = editorExperiment('platform_synced_block', true) ? PARENT_WITH_END_DROP_TARGET_NEXT : PARENT_WITH_END_DROP_TARGET;
248
237
  if (parent.lastChild === node && !isEmptyParagraph(node) && parentTypesWithEndDropTarget.includes(parent.type.name)) {
@@ -105,32 +105,28 @@ const destroyFn = (api, editorView) => {
105
105
  (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
106
106
  tr
107
107
  }) => {
108
- var _api$userIntent;
109
- const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true);
110
- if (isMultiSelect) {
111
- var _api$blockControls, _api$selection;
112
- const {
113
- multiSelectDnD
114
- } = ((_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {};
115
- // Restore the users initial Editor selection when the drop completes
116
- if (multiSelectDnD) {
117
- // If the TextSelection between the drag start and end has changed, the document has changed, and we should not reapply the last selection
118
- const expandedSelectionUnchanged = multiSelectDnD.textAnchor === tr.selection.anchor && multiSelectDnD.textHead === tr.selection.head;
119
- if (expandedSelectionUnchanged) {
120
- const $anchor = tr.doc.resolve(multiSelectDnD.userAnchor);
121
- const $head = tr.doc.resolve(multiSelectDnD.userHead);
122
- if ($head.node() === $anchor.node()) {
123
- const $from = $anchor.min($head);
124
- selectNode(tr, $from.pos, $from.node().type.name, api);
125
- } else {
126
- tr.setSelection(TextSelection.create(tr.doc, multiSelectDnD.userAnchor, multiSelectDnD.userHead));
127
- }
108
+ var _api$blockControls, _api$selection, _api$userIntent;
109
+ const {
110
+ multiSelectDnD
111
+ } = ((_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {};
112
+ // Restore the users initial Editor selection when the drop completes
113
+ if (multiSelectDnD) {
114
+ // If the TextSelection between the drag start and end has changed, the document has changed, and we should not reapply the last selection
115
+ const expandedSelectionUnchanged = multiSelectDnD.textAnchor === tr.selection.anchor && multiSelectDnD.textHead === tr.selection.head;
116
+ if (expandedSelectionUnchanged) {
117
+ const $anchor = tr.doc.resolve(multiSelectDnD.userAnchor);
118
+ const $head = tr.doc.resolve(multiSelectDnD.userHead);
119
+ if ($head.node() === $anchor.node()) {
120
+ const $from = $anchor.min($head);
121
+ selectNode(tr, $from.pos, $from.node().type.name, api);
122
+ } else {
123
+ tr.setSelection(TextSelection.create(tr.doc, multiSelectDnD.userAnchor, multiSelectDnD.userHead));
128
124
  }
129
125
  }
130
- (_api$selection = api.selection) === null || _api$selection === void 0 ? void 0 : _api$selection.commands.clearManualSelection()({
131
- tr
132
- });
133
126
  }
127
+ (_api$selection = api.selection) === null || _api$selection === void 0 ? void 0 : _api$selection.commands.clearManualSelection()({
128
+ tr
129
+ });
134
130
  const {
135
131
  start
136
132
  } = source.data;
@@ -138,15 +134,13 @@ const destroyFn = (api, editorView) => {
138
134
  const lastDragCancelled = location.current.dropTargets.length === 0;
139
135
  if (lastDragCancelled) {
140
136
  var _api$analytics2;
141
- let nodeTypes, hasSelectedMultipleNodes;
142
- if (isMultiSelect) {
143
- const position = getSelectedSlicePosition(start, tr, api);
144
- const attributes = getMultiSelectAnalyticsAttributes(tr, position.from, position.to);
145
- nodeTypes = attributes.nodeTypes;
146
- hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes;
147
- }
137
+ const position = getSelectedSlicePosition(start, tr, api);
138
+ const attributes = getMultiSelectAnalyticsAttributes(tr, position.from, position.to);
139
+ const {
140
+ nodeTypes,
141
+ hasSelectedMultipleNodes
142
+ } = attributes;
148
143
  const resolvedMovingNode = tr.doc.resolve(start);
149
- const maybeNode = resolvedMovingNode.nodeAfter;
150
144
  (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.attachAnalyticsEvent({
151
145
  eventType: EVENT_TYPE.UI,
152
146
  action: ACTION.CANCELLED,
@@ -154,11 +148,8 @@ const destroyFn = (api, editorView) => {
154
148
  actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
155
149
  attributes: {
156
150
  nodeDepth: resolvedMovingNode.depth,
157
- nodeType: (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name) || '',
158
- ...(isMultiSelect && {
159
- nodeTypes,
160
- hasSelectedMultipleNodes
161
- })
151
+ nodeTypes: nodeTypes || '',
152
+ hasSelectedMultipleNodes
162
153
  }
163
154
  })(tr);
164
155
  }
@@ -328,7 +319,7 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
328
319
  };
329
320
  }
330
321
  }
331
- if (multiSelectDnD && flags.isMultiSelectEnabled) {
322
+ if (multiSelectDnD) {
332
323
  multiSelectDnD.anchor = tr.mapping.map(multiSelectDnD.anchor);
333
324
  multiSelectDnD.head = tr.mapping.map(multiSelectDnD.head);
334
325
  }
@@ -337,7 +328,7 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
337
328
  isResizerResizing = resizerMeta !== null && resizerMeta !== void 0 ? resizerMeta : isResizerResizing;
338
329
  const hasJustFinishedResizing = resizerMeta === false;
339
330
  multiSelectDnD = (_meta$multiSelectDnD = meta === null || meta === void 0 ? void 0 : meta.multiSelectDnD) !== null && _meta$multiSelectDnD !== void 0 ? _meta$multiSelectDnD : multiSelectDnD;
340
- if (multiSelectDnD && flags.isMultiSelectEnabled) {
331
+ if (multiSelectDnD) {
341
332
  var _meta$isDragging;
342
333
  if (((_meta$isDragging = meta === null || meta === void 0 ? void 0 : meta.isDragging) !== null && _meta$isDragging !== void 0 ? _meta$isDragging : isDragging) && expValEquals('platform_editor_block_controls_perf_optimization', 'isEnabled', true)) {
343
334
  // When dragging, we want to keep the multiSelectDnD object unless both document and selection
@@ -694,12 +685,8 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
694
685
  const isAdvancedLayoutEnabled = editorExperiment('advanced_layouts', true, {
695
686
  exposure: true
696
687
  });
697
- const isMultiSelectEnabled = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
698
- exposure: true
699
- });
700
688
  const toolbarFlagsEnabled = areToolbarFlagsEnabled(Boolean(api === null || api === void 0 ? void 0 : api.toolbar));
701
689
  const flags = {
702
- isMultiSelectEnabled,
703
690
  toolbarFlagsEnabled
704
691
  };
705
692
  let anchorRectCache;
@@ -754,7 +741,7 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
754
741
  const tr = state.tr;
755
742
  let pluginState = key.getState(state);
756
743
  const dndDragCancelled = (_pluginState = pluginState) === null || _pluginState === void 0 ? void 0 : _pluginState.lastDragCancelled;
757
- if ((_pluginState2 = pluginState) !== null && _pluginState2 !== void 0 && _pluginState2.isPMDragging || dndDragCancelled && isMultiSelectEnabled) {
744
+ if ((_pluginState2 = pluginState) !== null && _pluginState2 !== void 0 && _pluginState2.isPMDragging || dndDragCancelled) {
758
745
  if (fg('platform_editor_ease_of_use_metrics')) {
759
746
  var _api$metrics2;
760
747
  api === null || api === void 0 ? void 0 : (_api$metrics2 = api.metrics) === null || _api$metrics2 === void 0 ? void 0 : _api$metrics2.commands.startActiveSessionTimer()({
@@ -774,7 +761,7 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
774
761
  // Currently we can only drag one node at a time
775
762
  // so we only need to check first child
776
763
  const draggable = dragging === null || dragging === void 0 ? void 0 : dragging.slice.content.firstChild;
777
- if (dndDragCancelled && isMultiSelectEnabled || (draggable === null || draggable === void 0 ? void 0 : draggable.type.name) === 'layoutColumn') {
764
+ if (dndDragCancelled || (draggable === null || draggable === void 0 ? void 0 : draggable.type.name) === 'layoutColumn') {
778
765
  // we prevent native DnD for layoutColumn to prevent single column layout.
779
766
  event.preventDefault();
780
767
  return false;
@@ -905,56 +892,33 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
905
892
  if (api !== null && api !== void 0 && (_api$limitedMode8 = api.limitedMode) !== null && _api$limitedMode8 !== void 0 && (_api$limitedMode8$sha = _api$limitedMode8.sharedState.currentState()) !== null && _api$limitedMode8$sha !== void 0 && _api$limitedMode8$sha.enabled) {
906
893
  return;
907
894
  }
908
- if (isMultiSelectEnabled) {
909
- if (event.shiftKey && event.ctrlKey) {
910
- //prevent holding down key combo from firing repeatedly
911
- if (!event.repeat && boundKeydownHandler(api, formatMessage)(view, event)) {
912
- event.preventDefault();
913
- return true;
914
- }
915
- }
916
- if ((event.key === 'Enter' || event.key === ' ') && event.target instanceof HTMLElement && editorExperiment('platform_editor_controls', 'variant1')) {
917
- const isDragHandle = event.target.closest(editorExperiment('platform_editor_block_menu', true) ? DRAG_HANDLE_SELECTOR : '[data-editor-block-ctrl-drag-handle="true"]') !== null;
918
- api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.setSelectedViaDragHandle(isDragHandle));
895
+ if (event.shiftKey && event.ctrlKey) {
896
+ //prevent holding down key combo from firing repeatedly
897
+ if (!event.repeat && boundKeydownHandler(api, formatMessage)(view, event)) {
898
+ event.preventDefault();
899
+ return true;
919
900
  }
920
- if ((event.key === 'ArrowLeft' || event.key === 'ArrowRight' || event.key === 'ArrowDown' || event.key === 'ArrowUp') && editorExperiment('platform_editor_controls', 'variant1')) {
921
- var _api$blockControls$sh2, _api$blockControls$sh3;
922
- const isBlockMenuOpen = (api === null || api === void 0 ? void 0 : (_api$blockControls$sh2 = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh2 === void 0 ? void 0 : _api$blockControls$sh2.isMenuOpen) && editorExperiment('platform_editor_block_menu', true);
923
- // when block menu is just open, and we press arrow keys, we want to use the arrow keys to navigate the block menu
924
- // in this scenario, isSelectedViaDragHandle should not be set to false
925
- if (api !== null && api !== void 0 && (_api$blockControls$sh3 = api.blockControls.sharedState.currentState()) !== null && _api$blockControls$sh3 !== void 0 && _api$blockControls$sh3.isSelectedViaDragHandle && !isBlockMenuOpen) {
926
- api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.setSelectedViaDragHandle(false));
927
- }
928
- }
929
- if (!event.repeat && event.shiftKey && fg('platform_editor_elements_dnd_shift_click_select')) {
930
- view.dispatch(view.state.tr.setMeta(key, {
931
- ...view.state.tr.getMeta(key),
932
- isShiftDown: true
933
- }));
934
- }
935
- return false;
936
- } else {
937
- if (event.shiftKey && event.ctrlKey) {
938
- //prevent holding down key combo from firing repeatedly
939
- if (!event.repeat && boundKeydownHandler(api, formatMessage)(view, event)) {
940
- event.preventDefault();
941
- return true;
942
- }
943
- }
944
- if ((event.key === 'Enter' || event.key === ' ') && event.target instanceof HTMLElement && editorExperiment('platform_editor_controls', 'variant1')) {
945
- const isDragHandle = event.target.closest(editorExperiment('platform_editor_block_menu', true) ? DRAG_HANDLE_SELECTOR : '[data-editor-block-ctrl-drag-handle="true"]') !== null;
946
- api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.setSelectedViaDragHandle(isDragHandle));
947
- }
948
- if ((event.key === 'ArrowLeft' || event.key === 'ArrowRight' || event.key === 'ArrowDown' || event.key === 'ArrowUp') && editorExperiment('platform_editor_controls', 'variant1')) {
949
- var _api$blockControls$sh4, _api$blockControls$sh5;
950
- const isBlockMenuOpen = (api === null || api === void 0 ? void 0 : (_api$blockControls$sh4 = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh4 === void 0 ? void 0 : _api$blockControls$sh4.isMenuOpen) && editorExperiment('platform_editor_block_menu', true);
951
- // when block menu is just open, and we press arrow keys, we want to use the arrow keys to navigate the block menu
952
- // in this scenario, isSelectedViaDragHandle should not be set to false
953
- if (api !== null && api !== void 0 && (_api$blockControls$sh5 = api.blockControls.sharedState.currentState()) !== null && _api$blockControls$sh5 !== void 0 && _api$blockControls$sh5.isSelectedViaDragHandle && !isBlockMenuOpen) {
954
- api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.setSelectedViaDragHandle(false));
955
- }
901
+ }
902
+ if ((event.key === 'Enter' || event.key === ' ') && event.target instanceof HTMLElement && editorExperiment('platform_editor_controls', 'variant1')) {
903
+ const isDragHandle = event.target.closest(editorExperiment('platform_editor_block_menu', true) ? DRAG_HANDLE_SELECTOR : '[data-editor-block-ctrl-drag-handle="true"]') !== null;
904
+ api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.setSelectedViaDragHandle(isDragHandle));
905
+ }
906
+ if ((event.key === 'ArrowLeft' || event.key === 'ArrowRight' || event.key === 'ArrowDown' || event.key === 'ArrowUp') && editorExperiment('platform_editor_controls', 'variant1')) {
907
+ var _api$blockControls$sh2, _api$blockControls$sh3;
908
+ const isBlockMenuOpen = (api === null || api === void 0 ? void 0 : (_api$blockControls$sh2 = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh2 === void 0 ? void 0 : _api$blockControls$sh2.isMenuOpen) && editorExperiment('platform_editor_block_menu', true);
909
+ // when block menu is just open, and we press arrow keys, we want to use the arrow keys to navigate the block menu
910
+ // in this scenario, isSelectedViaDragHandle should not be set to false
911
+ if (api !== null && api !== void 0 && (_api$blockControls$sh3 = api.blockControls.sharedState.currentState()) !== null && _api$blockControls$sh3 !== void 0 && _api$blockControls$sh3.isSelectedViaDragHandle && !isBlockMenuOpen) {
912
+ api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.setSelectedViaDragHandle(false));
956
913
  }
957
914
  }
915
+ if (!event.repeat && event.shiftKey && fg('platform_editor_elements_dnd_shift_click_select')) {
916
+ view.dispatch(view.state.tr.setMeta(key, {
917
+ ...view.state.tr.getMeta(key),
918
+ isShiftDown: true
919
+ }));
920
+ }
921
+ return false;
958
922
  },
959
923
  keyup(view, event) {
960
924
  var _api$limitedMode9, _api$limitedMode9$sha;
@@ -1,6 +1,6 @@
1
1
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
2
  import { fg } from '@atlaskit/platform-feature-flags';
3
- export const attachMoveNodeAnalytics = (tr, inputMethod, fromDepth, fromNodeType, toDepth, toNodeType, isSameParent, api, fromNodeTypes, hasSelectedMultipleNodes) => {
3
+ export const attachMoveNodeAnalytics = (tr, inputMethod, fromDepth, fromNodeTypes, toDepth, toNodeType, isSameParent, api, hasSelectedMultipleNodes) => {
4
4
  var _api$analytics, _api$analytics$action;
5
5
  return api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : (_api$analytics$action = _api$analytics.actions) === null || _api$analytics$action === void 0 ? void 0 : _api$analytics$action.attachAnalyticsEvent({
6
6
  eventType: EVENT_TYPE.TRACK,
@@ -9,7 +9,6 @@ export const attachMoveNodeAnalytics = (tr, inputMethod, fromDepth, fromNodeType
9
9
  actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
10
10
  attributes: {
11
11
  nodeDepth: fromDepth,
12
- nodeType: fromNodeType,
13
12
  nodeTypes: fromNodeTypes,
14
13
  hasSelectedMultipleNodes,
15
14
  destinationNodeDepth: toDepth,