@atlaskit/editor-plugin-block-controls 3.0.0 → 3.1.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/blockControlsPlugin.js +27 -14
  3. package/dist/cjs/editor-commands/move-node.js +15 -18
  4. package/dist/cjs/pm-plugins/decorations-common.js +2 -4
  5. package/dist/cjs/pm-plugins/main.js +73 -34
  6. package/dist/cjs/pm-plugins/utils/getSelection.js +1 -1
  7. package/dist/cjs/pm-plugins/utils/selection.js +34 -4
  8. package/dist/cjs/ui/consts.js +9 -1
  9. package/dist/cjs/ui/drag-handle.js +69 -36
  10. package/dist/es2019/blockControlsPlugin.js +27 -14
  11. package/dist/es2019/editor-commands/move-node.js +17 -20
  12. package/dist/es2019/pm-plugins/decorations-common.js +2 -4
  13. package/dist/es2019/pm-plugins/main.js +70 -23
  14. package/dist/es2019/pm-plugins/utils/getSelection.js +1 -1
  15. package/dist/es2019/pm-plugins/utils/selection.js +33 -3
  16. package/dist/es2019/ui/consts.js +8 -0
  17. package/dist/es2019/ui/drag-handle.js +59 -30
  18. package/dist/esm/blockControlsPlugin.js +27 -14
  19. package/dist/esm/editor-commands/move-node.js +16 -19
  20. package/dist/esm/pm-plugins/decorations-common.js +2 -4
  21. package/dist/esm/pm-plugins/main.js +71 -32
  22. package/dist/esm/pm-plugins/utils/getSelection.js +1 -1
  23. package/dist/esm/pm-plugins/utils/selection.js +33 -3
  24. package/dist/esm/ui/consts.js +8 -0
  25. package/dist/esm/ui/drag-handle.js +70 -37
  26. package/dist/types/blockControlsPluginType.d.ts +2 -0
  27. package/dist/types/pm-plugins/main.d.ts +2 -1
  28. package/dist/types/pm-plugins/utils/selection.d.ts +13 -1
  29. package/dist/types/ui/consts.d.ts +7 -0
  30. package/dist/types-ts4.5/blockControlsPluginType.d.ts +2 -0
  31. package/dist/types-ts4.5/pm-plugins/main.d.ts +2 -1
  32. package/dist/types-ts4.5/pm-plugins/utils/selection.d.ts +13 -1
  33. package/dist/types-ts4.5/ui/consts.d.ts +7 -0
  34. package/package.json +4 -4
@@ -1,3 +1,4 @@
1
+ import { TextSelection, NodeSelection } from '@atlaskit/editor-prosemirror/state';
1
2
  import { key } from '../main';
2
3
  export const getMultiSelectionIfPosInside = (api, pos, tr) => {
3
4
  var _api$blockControls, _pluginState$multiSel, _tr$getMeta;
@@ -10,7 +11,7 @@ export const getMultiSelectionIfPosInside = (api, pos, tr) => {
10
11
  const multiTo = Math.max(multiSelectDnD.anchor, multiSelectDnD.head);
11
12
 
12
13
  // We subtract one as the handle position is before the node
13
- return pos >= multiFrom - 1 && pos <= multiTo ? {
14
+ return pos >= multiFrom - 1 && pos < multiTo ? {
14
15
  anchor: multiSelectDnD.anchor,
15
16
  head: multiSelectDnD.head
16
17
  } : {};
@@ -29,12 +30,41 @@ export const getSelectedSlicePosition = (handlePos, tr, api) => {
29
30
  head
30
31
  } = getMultiSelectionIfPosInside(api, handlePos, tr);
31
32
  const inSelection = anchor !== undefined && head !== undefined;
32
- const from = inSelection ? Math.min(anchor, head) : handlePos;
33
+ const from = inSelection ? Math.min(anchor || 0, head || 0) : handlePos;
33
34
  const activeNode = tr.doc.nodeAt(handlePos);
34
35
  const activeNodeEndPos = handlePos + ((_activeNode$nodeSize = activeNode === null || activeNode === void 0 ? void 0 : activeNode.nodeSize) !== null && _activeNode$nodeSize !== void 0 ? _activeNode$nodeSize : 1);
35
- const to = inSelection ? Math.max(anchor, head) : activeNodeEndPos;
36
+ const to = inSelection ? Math.max(anchor || 0, head || 0) : activeNodeEndPos;
36
37
  return {
37
38
  from,
38
39
  to
39
40
  };
41
+ };
42
+
43
+ /**
44
+ * Takes a position and expands the selection to encompass the node at that position. Ignores empty or out of range selections.
45
+ * Ignores positions that are in text blocks (i.e. not start of a node)
46
+ * @returns TextSelection if expanded, otherwise returns Selection that was passed in.
47
+ */
48
+ export const expandSelectionHeadToNodeAtPos = (selection, nodePos) => {
49
+ const doc = selection.$anchor.doc;
50
+ if (nodePos < 0 || nodePos > doc.nodeSize - 2 || selection.empty) {
51
+ return selection;
52
+ }
53
+ const $pos = doc.resolve(nodePos);
54
+ const node = $pos.nodeAfter;
55
+ if ($pos.node().isTextblock || !node) {
56
+ return selection;
57
+ }
58
+ const $newHead = nodePos < selection.anchor ? $pos : doc.resolve(node.nodeSize + nodePos);
59
+ const textSelection = new TextSelection(selection.$anchor, $newHead);
60
+ return textSelection;
61
+ };
62
+
63
+ /**
64
+ * This swaps the anchor/head for NodeSelections when its anchor > pos.
65
+ * This is because NodeSelection always has an anchor at the start of the node,
66
+ * which may not align with the existing selection.
67
+ */
68
+ export const alignAnchorHeadInDirectionOfPos = (selection, pos) => {
69
+ return selection instanceof NodeSelection && Math.max(pos, selection.anchor) === selection.anchor ? new TextSelection(selection.$head, selection.$anchor) : selection;
40
70
  };
@@ -18,6 +18,14 @@ export const DRAG_HANDLE_H5_TOP_ADJUSTMENT = 3;
18
18
  export const DRAG_HANDLE_H6_TOP_ADJUSTMENT = 3;
19
19
  export const DRAG_HANDLE_LAYOUT_SECTION_TOP_ADJUSTMENT = 8;
20
20
  export const DRAG_HANDLE_PARAGRAPH_TOP_ADJUSTMENT = 2;
21
+
22
+ /** We only want to shift-select nodes that are at the top level of a document.
23
+ * This is because funky things happen when selecting inside of tableCells, but we
24
+ * also want to avoid heavily nested cases to descope potential corner cases.
25
+ * Various top level nodes have their selection 'from' at depths other than 0,
26
+ * so we allow for some leniency to capture them all. e.g. Table is depth 3.
27
+ */
28
+ export const DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH = 3;
21
29
  const nodeTypeExcludeList = ['embedCard', 'mediaSingle', 'table'];
22
30
  export const dragHandleGap = (nodeType, parentNodeType) => {
23
31
  if (nodeType === 'layoutSection' && fg('platform_editor_advanced_layouts_post_fix_patch_2')) {
@@ -25,7 +25,8 @@ import { key } from '../pm-plugins/main';
25
25
  import { getMultiSelectAnalyticsAttributes } from '../pm-plugins/utils/analytics';
26
26
  import { getLeftPosition, getTopPosition } from '../pm-plugins/utils/drag-handle-positions';
27
27
  import { isHandleCorrelatedToSelection, selectNode } from '../pm-plugins/utils/getSelection';
28
- import { DRAG_HANDLE_BORDER_RADIUS, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_WIDTH, DRAG_HANDLE_ZINDEX, dragHandleGap, nodeMargins, spacingBetweenNodesForPreview, topPositionAdjustment } from './consts';
28
+ import { alignAnchorHeadInDirectionOfPos, expandSelectionHeadToNodeAtPos } from '../pm-plugins/utils/selection';
29
+ import { DRAG_HANDLE_BORDER_RADIUS, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH, DRAG_HANDLE_WIDTH, DRAG_HANDLE_ZINDEX, dragHandleGap, nodeMargins, spacingBetweenNodesForPreview, topPositionAdjustment } from './consts';
29
30
  import { dragPreview } from './drag-preview';
30
31
  const iconWrapperStyles = xcss({
31
32
  display: 'flex',
@@ -61,6 +62,13 @@ const dragHandleButtonStyles = css({
61
62
  },
62
63
  '&:focus': {
63
64
  outline: `2px solid ${"var(--ds-border-focused, #388BFF)"}`
65
+ },
66
+ '&:disabled': {
67
+ color: "var(--ds-icon-disabled, #8993A4)",
68
+ backgroundColor: 'transparent'
69
+ },
70
+ '&:hover:disabled': {
71
+ backgroundColor: "var(--ds-background-disabled, transparent)"
64
72
  }
65
73
  });
66
74
  const dragHandleMultiLineSelectionFixFirefox = css({
@@ -116,15 +124,18 @@ export const DragHandle = ({
116
124
  handleOptions,
117
125
  isTopLevelNode = true
118
126
  }) => {
119
- var _api$core2, _api$analytics2, _api$core4;
127
+ var _api$core2, _api$analytics2, _api$blockControls3, _api$core4;
120
128
  const start = getPos();
121
129
  const buttonRef = useRef(null);
122
130
  const [blockCardWidth, setBlockCardWidth] = useState(768);
123
131
  const [dragHandleSelected, setDragHandleSelected] = useState(false);
132
+ const [dragHandleDisabled, setDragHandleDisabled] = useState(false);
124
133
  const {
125
134
  featureFlagsState
126
135
  } = useSharedPluginState(api, ['featureFlags']);
127
136
  const selection = useSharedPluginStateSelector(api, 'selection.selection');
137
+ const isShiftDown = useSharedPluginStateSelector(api, 'blockControls.isShiftDown');
138
+ const multiSelectDnD = useSharedPluginStateSelector(api, 'blockControls.multiSelectDnD');
128
139
  const isLayoutColumn = nodeType === 'layoutColumn';
129
140
  const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
130
141
  exposure: true
@@ -144,9 +155,11 @@ export const DragHandle = ({
144
155
  }
145
156
  }
146
157
  }, [anchorName, nodeType, view.dom]);
147
- const handleOnClick = useCallback(() => {
158
+ const handleOnClick = useCallback(e => {
148
159
  var _api$core;
149
- setDragHandleSelected(!dragHandleSelected);
160
+ if (!isMultiSelect) {
161
+ setDragHandleSelected(!dragHandleSelected);
162
+ }
150
163
  api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
151
164
  tr
152
165
  }) => {
@@ -155,7 +168,24 @@ export const DragHandle = ({
155
168
  if (startPos === undefined) {
156
169
  return tr;
157
170
  }
158
- tr = selectNode(tr, startPos, nodeType);
171
+ const $anchor = (multiSelectDnD === null || multiSelectDnD === void 0 ? void 0 : multiSelectDnD.anchor) !== undefined ? tr.doc.resolve(multiSelectDnD === null || multiSelectDnD === void 0 ? void 0 : multiSelectDnD.anchor) : tr.selection.$anchor;
172
+ if (!isMultiSelect || tr.selection.empty || !e.shiftKey) {
173
+ tr = selectNode(tr, startPos, nodeType);
174
+ if (editorExperiment('platform_editor_controls', 'variant1')) {
175
+ var _api$blockControls;
176
+ api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.commands.toggleBlockMenu()({
177
+ tr
178
+ });
179
+ }
180
+ } else if (isTopLevelNode && $anchor.depth <= DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH && e.shiftKey) {
181
+ var _api$blockControls2;
182
+ const alignAnchorHeadToSel = alignAnchorHeadInDirectionOfPos(tr.selection, startPos);
183
+ const selectionWithExpandedHead = expandSelectionHeadToNodeAtPos(alignAnchorHeadToSel, startPos);
184
+ tr.setSelection(selectionWithExpandedHead);
185
+ api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.setMultiSelectPositions()({
186
+ tr
187
+ });
188
+ }
159
189
  const resolvedMovingNode = tr.doc.resolve(startPos);
160
190
  const maybeNode = resolvedMovingNode.nodeAfter;
161
191
  tr.setMeta('scrollIntoView', false);
@@ -172,14 +202,7 @@ export const DragHandle = ({
172
202
  return tr;
173
203
  });
174
204
  view.focus();
175
- if (editorExperiment('platform_editor_controls', 'variant1')) {
176
- const startPos = getPos();
177
- if (startPos === undefined) {
178
- return false;
179
- }
180
- api === null || api === void 0 ? void 0 : api.core.actions.execute(api.blockControls.commands.toggleBlockMenu());
181
- }
182
- }, [dragHandleSelected, api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions, api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions, api === null || api === void 0 ? void 0 : api.blockControls.commands, view, getPos, nodeType]);
205
+ }, [isMultiSelect, api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions, api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions, api === null || api === void 0 ? void 0 : (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands, view, dragHandleSelected, getPos, multiSelectDnD === null || multiSelectDnD === void 0 ? void 0 : multiSelectDnD.anchor, isTopLevelNode, nodeType]);
183
206
 
184
207
  // TODO - This needs to be investigated further. Drag preview generation is not always working
185
208
  // as expected with a node selection. This workaround sets the selection to the node on mouseDown,
@@ -199,7 +222,6 @@ export const DragHandle = ({
199
222
  const handleKeyDown = useCallback(e => {
200
223
  if (fg('platform_editor_element_drag_and_drop_ed_23873')) {
201
224
  // allow user to use spacebar to select the node
202
-
203
225
  if (!e.repeat && e.key === ' ') {
204
226
  var _api$core3;
205
227
  const startPos = getPos();
@@ -216,9 +238,9 @@ export const DragHandle = ({
216
238
  const $startPos = tr.doc.resolve(startPos + node.nodeSize);
217
239
  const selection = new TextSelection($startPos);
218
240
  tr.setSelection(selection);
219
- tr.setMeta(key, {
241
+ !isMultiSelect && tr.setMeta(key, {
220
242
  pos: startPos
221
- }); ////WHERE IS THIS USED?
243
+ });
222
244
  return tr;
223
245
  });
224
246
  } else if (![e.altKey, e.ctrlKey, e.shiftKey].some(pressed => pressed)) {
@@ -227,7 +249,7 @@ export const DragHandle = ({
227
249
  view.focus();
228
250
  }
229
251
  }
230
- }, [getPos, api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, view]);
252
+ }, [getPos, api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, isMultiSelect, view]);
231
253
  useEffect(() => {
232
254
  const element = buttonRef.current;
233
255
  if (!element) {
@@ -242,7 +264,6 @@ export const DragHandle = ({
242
264
  onGenerateDragPreview: ({
243
265
  nativeSetDragImage
244
266
  }) => {
245
- var _api$blockControls2;
246
267
  if (isMultiSelect) {
247
268
  var _api$core5;
248
269
  api === null || api === void 0 ? void 0 : (_api$core5 = api.core) === null || _api$core5 === void 0 ? void 0 : _api$core5.actions.execute(({
@@ -253,8 +274,8 @@ export const DragHandle = ({
253
274
  return tr;
254
275
  }
255
276
  if (!tr.selection.empty && handlePos >= tr.selection.$from.start() - 1 && handlePos <= tr.selection.to) {
256
- var _api$blockControls;
257
- api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.commands.setMultiSelectPositions()({
277
+ var _api$blockControls4;
278
+ api === null || api === void 0 ? void 0 : (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 ? void 0 : _api$blockControls4.commands.setMultiSelectPositions()({
258
279
  tr
259
280
  });
260
281
  }
@@ -267,9 +288,6 @@ export const DragHandle = ({
267
288
  doc,
268
289
  selection
269
290
  } = state;
270
- const {
271
- multiSelectDnD
272
- } = (api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.sharedState.currentState()) || {};
273
291
  let sliceFrom = selection.from;
274
292
  let sliceTo = selection.to;
275
293
  if (multiSelectDnD) {
@@ -281,7 +299,7 @@ export const DragHandle = ({
281
299
  sliceTo = Math.max(anchor, head);
282
300
  }
283
301
  const expandedSlice = doc.slice(sliceFrom, sliceTo);
284
- const isDraggingMultiLine = isMultiSelect && startPos !== undefined && startPos >= sliceFrom && startPos <= sliceTo && expandedSlice.content.childCount > 1;
302
+ const isDraggingMultiLine = isMultiSelect && startPos !== undefined && startPos >= sliceFrom && startPos < sliceTo && expandedSlice.content.childCount > 1;
285
303
  setCustomNativeDragPreview({
286
304
  getOffset: () => {
287
305
  if (!isDraggingMultiLine) {
@@ -369,11 +387,10 @@ export const DragHandle = ({
369
387
  api === null || api === void 0 ? void 0 : (_api$core6 = api.core) === null || _api$core6 === void 0 ? void 0 : _api$core6.actions.execute(({
370
388
  tr
371
389
  }) => {
372
- var _tr$getMeta, _api$blockControls3, _api$analytics3;
390
+ var _api$blockControls5, _api$analytics3;
373
391
  let nodeTypes, hasSelectedMultipleNodes;
374
392
  const resolvedMovingNode = tr.doc.resolve(start);
375
393
  const maybeNode = resolvedMovingNode.nodeAfter;
376
- const multiSelectDnD = (_tr$getMeta = tr.getMeta(key)) === null || _tr$getMeta === void 0 ? void 0 : _tr$getMeta.multiSelectDnD;
377
394
  if (multiSelectDnD) {
378
395
  const attributes = getMultiSelectAnalyticsAttributes(tr, multiSelectDnD.anchor, multiSelectDnD.head);
379
396
  nodeTypes = attributes.nodeTypes;
@@ -382,7 +399,7 @@ export const DragHandle = ({
382
399
  nodeTypes = maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name;
383
400
  hasSelectedMultipleNodes = false;
384
401
  }
385
- api === null || api === void 0 ? void 0 : (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands.setNodeDragged(getPos, anchorName, nodeType)({
402
+ api === null || api === void 0 ? void 0 : (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 ? void 0 : _api$blockControls5.commands.setNodeDragged(getPos, anchorName, nodeType)({
386
403
  tr
387
404
  });
388
405
  tr.setMeta('scrollIntoView', false);
@@ -405,7 +422,7 @@ export const DragHandle = ({
405
422
  view.focus();
406
423
  }
407
424
  });
408
- }, [anchorName, api, getPos, isMultiSelect, nodeType, start, view]);
425
+ }, [anchorName, api, getPos, isMultiSelect, multiSelectDnD, nodeType, start, view]);
409
426
  const macroInteractionUpdates = featureFlagsState === null || featureFlagsState === void 0 ? void 0 : featureFlagsState.macroInteractionUpdates;
410
427
  const calculatePosition = useCallback(() => {
411
428
  let parentNodeType;
@@ -492,6 +509,17 @@ export const DragHandle = ({
492
509
  }
493
510
  setDragHandleSelected(isHandleCorrelatedToSelection(view.state, selection, start));
494
511
  }, [start, selection, view.state, isMultiSelect]);
512
+ useEffect(() => {
513
+ if (!isMultiSelect || isShiftDown === undefined || view.state.selection.empty) {
514
+ return;
515
+ }
516
+ const $anchor = (multiSelectDnD === null || multiSelectDnD === void 0 ? void 0 : multiSelectDnD.anchor) !== undefined ? view.state.doc.resolve(multiSelectDnD === null || multiSelectDnD === void 0 ? void 0 : multiSelectDnD.anchor) : view.state.selection.$anchor;
517
+ if (isShiftDown && (!isTopLevelNode || isTopLevelNode && $anchor.depth > DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH)) {
518
+ setDragHandleDisabled(true);
519
+ } else {
520
+ setDragHandleDisabled(false);
521
+ }
522
+ }, [isMultiSelect, isShiftDown, isTopLevelNode, multiSelectDnD === null || multiSelectDnD === void 0 ? void 0 : multiSelectDnD.anchor, view.state.doc, view.state.selection]);
495
523
  let helpDescriptors = isTopLevelNode && fg('platform_editor_advanced_layouts_accessibility') ? [{
496
524
  description: formatMessage(blockControlsMessages.dragToMove)
497
525
  }, {
@@ -578,6 +606,7 @@ export const DragHandle = ({
578
606
  // eslint-disable-next-line @atlaskit/design-system/no-direct-use-of-web-platform-drag-and-drop
579
607
  ,
580
608
  onDrop: handleOnDrop,
609
+ disabled: dragHandleDisabled,
581
610
  "data-testid": "block-ctrl-drag-handle"
582
611
  }, jsx(Box, {
583
612
  as: "span",
@@ -585,11 +614,11 @@ export const DragHandle = ({
585
614
  // eslint-disable-next-line @atlaskit/design-system/no-direct-use-of-web-platform-drag-and-drop
586
615
  ,
587
616
  onDragStart: handleIconDragStart
588
- }, ' ', jsx(DragHandlerIcon, {
617
+ }, jsx(DragHandlerIcon, {
589
618
  label: "",
590
619
  size: "medium"
591
620
  })));
592
- return fg('platform_editor_element_drag_and_drop_ed_23873') ? jsx(Tooltip, {
621
+ return !dragHandleDisabled && fg('platform_editor_element_drag_and_drop_ed_23873') ? jsx(Tooltip, {
593
622
  content: jsx(TooltipContentWithMultipleShortcuts, {
594
623
  helpDescriptors: helpDescriptors
595
624
  }),
@@ -8,6 +8,7 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
8
8
  import { moveNode } from './editor-commands/move-node';
9
9
  import { moveToLayout } from './editor-commands/move-to-layout';
10
10
  import { createPlugin, key } from './pm-plugins/main';
11
+ import { selectNode } from './pm-plugins/utils/getSelection';
11
12
  import BlockMenu from './ui/block-menu';
12
13
  import { DragHandleMenu } from './ui/drag-handle-menu';
13
14
  import { GlobalStylesWrapper } from './ui/global-styles';
@@ -81,29 +82,40 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
81
82
  },
82
83
  setMultiSelectPositions: function setMultiSelectPositions(anchor, head) {
83
84
  return function (_ref6) {
84
- var _api$selection;
85
+ var _api$selection, _$to$nodeBefore, _$from$nodeAfter;
85
86
  var tr = _ref6.tr;
86
87
  var _tr$selection = tr.selection,
87
88
  userAnchor = _tr$selection.anchor,
88
89
  userHead = _tr$selection.head;
89
- var expandedAnchor, expandedHead;
90
+ var $expandedAnchor, $expandedHead;
90
91
  if (anchor !== undefined && head !== undefined) {
91
- expandedAnchor = tr.doc.resolve(anchor);
92
- expandedHead = tr.doc.resolve(head);
92
+ $expandedAnchor = tr.doc.resolve(anchor);
93
+ $expandedHead = tr.doc.resolve(head);
93
94
  } else {
94
95
  var expandedSelection = expandSelectionBounds(tr.selection.$anchor, tr.selection.$head);
95
- expandedAnchor = expandedSelection.$anchor;
96
- expandedHead = expandedSelection.$head;
96
+ $expandedAnchor = expandedSelection.$anchor;
97
+ $expandedHead = expandedSelection.$head;
97
98
  }
98
- api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || _api$selection.commands.setManualSelection(expandedAnchor.pos, expandedHead.pos)({
99
+ api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || _api$selection.commands.setManualSelection($expandedAnchor.pos, $expandedHead.pos)({
99
100
  tr: tr
100
101
  });
101
- // this is to normalise the selection's boundaries to inline positions, preventing it from collapsing
102
- var expandedNormalisedSel = TextSelection.between(expandedAnchor, expandedHead);
103
- tr.setSelection(expandedNormalisedSel);
102
+ var $from = $expandedAnchor.min($expandedHead);
103
+ var $to = $expandedAnchor.max($expandedHead);
104
+ var expandedNormalisedSel;
105
+ if ($from.nodeAfter === $to.nodeBefore) {
106
+ selectNode(tr, $from.pos, $expandedAnchor.node().type.name);
107
+ expandedNormalisedSel = tr.selection;
108
+ } else if (((_$to$nodeBefore = $to.nodeBefore) === null || _$to$nodeBefore === void 0 ? void 0 : _$to$nodeBefore.type.name) === 'mediaSingle' || ((_$from$nodeAfter = $from.nodeAfter) === null || _$from$nodeAfter === void 0 ? void 0 : _$from$nodeAfter.type.name) === 'mediaSingle') {
109
+ expandedNormalisedSel = new TextSelection($expandedAnchor, $expandedHead);
110
+ tr.setSelection(expandedNormalisedSel);
111
+ } else {
112
+ // this is to normalise the selection's boundaries to inline positions, preventing it from collapsing
113
+ expandedNormalisedSel = TextSelection.between($expandedAnchor, $expandedHead);
114
+ tr.setSelection(expandedNormalisedSel);
115
+ }
104
116
  var multiSelectDnD = {
105
- anchor: expandedAnchor.pos,
106
- head: expandedHead.pos,
117
+ anchor: $expandedAnchor.pos,
118
+ head: $expandedHead.pos,
107
119
  textAnchor: expandedNormalisedSel.anchor,
108
120
  textHead: expandedNormalisedSel.head,
109
121
  userAnchor: userAnchor,
@@ -118,7 +130,7 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
118
130
  }
119
131
  },
120
132
  getSharedState: function getSharedState(editorState) {
121
- 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;
133
+ 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, _key$getState$isShift, _key$getState6;
122
134
  if (!editorState) {
123
135
  return undefined;
124
136
  }
@@ -127,7 +139,8 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
127
139
  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,
128
140
  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,
129
141
  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,
130
- 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
142
+ 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,
143
+ isShiftDown: (_key$getState$isShift = (_key$getState6 = key.getState(editorState)) === null || _key$getState6 === void 0 ? void 0 : _key$getState6.isShiftDown) !== null && _key$getState$isShift !== void 0 ? _key$getState$isShift : undefined
131
144
  };
132
145
  },
133
146
  contentComponent: function contentComponent(_ref7) {
@@ -4,7 +4,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
4
4
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
5
5
  import { expandedState } from '@atlaskit/editor-common/expand';
6
6
  import { blockControlsMessages } from '@atlaskit/editor-common/messages';
7
- import { GapCursorSelection, expandSelectionBounds } from '@atlaskit/editor-common/selection';
7
+ import { expandSelectionBounds, GapCursorSelection } from '@atlaskit/editor-common/selection';
8
8
  import { transformSliceNestedExpandToExpand } from '@atlaskit/editor-common/transforms';
9
9
  import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
10
10
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
@@ -54,16 +54,14 @@ var isDragLayoutColumnToTopLevel = function isDragLayoutColumnToTopLevel($from,
54
54
  * @returns the start position of a node if the node can be moved, otherwise -1
55
55
  */
56
56
  var getCurrentNodePos = function getCurrentNodePos(state) {
57
- var _activeNode$handleOpt;
58
57
  var selection = state.selection;
59
- var _ref = key.getState(state) || {},
60
- activeNode = _ref.activeNode;
61
58
  var currentNodePos = -1;
62
59
 
63
60
  // There are 3 cases when a node can be moved
64
- if (activeNode && (_activeNode$handleOpt = activeNode.handleOptions) !== null && _activeNode$handleOpt !== void 0 && _activeNode$handleOpt.isFocused) {
61
+ var focusedHandle = getFocusedHandle(state);
62
+ if (focusedHandle) {
65
63
  // 1. drag handle of the node is focused
66
- currentNodePos = activeNode.pos;
64
+ currentNodePos = focusedHandle.pos;
67
65
  } else if (isInTable(state)) {
68
66
  if (isTableSelected(selection)) {
69
67
  var _findTable$pos, _findTable;
@@ -81,6 +79,12 @@ var getCurrentNodePos = function getCurrentNodePos(state) {
81
79
  }
82
80
  return currentNodePos;
83
81
  };
82
+ var getFocusedHandle = function getFocusedHandle(state) {
83
+ var _activeNode$handleOpt;
84
+ var _ref = key.getState(state) || {},
85
+ activeNode = _ref.activeNode;
86
+ return activeNode && (_activeNode$handleOpt = activeNode.handleOptions) !== null && _activeNode$handleOpt !== void 0 && _activeNode$handleOpt.isFocused ? activeNode : undefined;
87
+ };
84
88
  export var moveNodeViaShortcut = function moveNodeViaShortcut(api, direction, formatMessage) {
85
89
  return function (state) {
86
90
  var isParentNodeOfTypeLayout;
@@ -90,20 +94,14 @@ export var moveNodeViaShortcut = function moveNodeViaShortcut(api, direction, fo
90
94
  isParentNodeOfTypeLayout = !!findParentNodeOfType([state.schema.nodes.layoutSection])(state.selection);
91
95
  }
92
96
  var isMultiSelectEnabled = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true);
93
- var expandedAnchor, expandedHead;
94
- var pluginState = api === null || api === void 0 ? void 0 : api.blockControls.sharedState.currentState();
95
- if (pluginState !== null && pluginState !== void 0 && pluginState.multiSelectDnD) {
96
- expandedAnchor = pluginState.multiSelectDnD.anchor;
97
- expandedHead = pluginState.multiSelectDnD.head;
98
- } else {
99
- var expandedSelection = expandSelectionBounds(selection.$anchor, selection.$head);
100
- expandedAnchor = expandedSelection.$anchor.pos;
101
- expandedHead = expandedSelection.$head.pos;
102
- }
103
- var currentNodePos = isMultiSelectEnabled ? Math.min(expandedAnchor, expandedHead) : getCurrentNodePos(state);
97
+ var expandedSelection = expandSelectionBounds(selection.$anchor, selection.$head);
98
+ var expandedAnchor = expandedSelection.$anchor.pos;
99
+ var expandedHead = expandedSelection.$head.pos;
100
+ var currentNodePos = isMultiSelectEnabled && !getFocusedHandle(state) ? Math.min(expandedAnchor, expandedHead) : getCurrentNodePos(state);
104
101
  if (currentNodePos > -1) {
105
102
  var _state$doc$nodeAt;
106
103
  var $pos = state.doc.resolve(currentNodePos);
104
+ var nodeAfterPos = isMultiSelectEnabled && !getFocusedHandle(state) ? Math.max(expandedAnchor, expandedHead) : $pos.posAtIndex($pos.index() + 1);
107
105
  var isTopLevelNode = $pos.depth === 0;
108
106
  var moveToPos = -1;
109
107
  var nodeIndex = $pos.index();
@@ -211,7 +209,6 @@ export var moveNodeViaShortcut = function moveNodeViaShortcut(api, direction, fo
211
209
  }
212
210
  } else {
213
211
  var _endOfDoc = $pos.end();
214
- var nodeAfterPos = isMultiSelectEnabled ? Math.max(expandedAnchor, expandedHead) : $pos.posAtIndex($pos.index() + 1);
215
212
  if (nodeAfterPos > _endOfDoc) {
216
213
  return false;
217
214
  }
@@ -290,8 +287,8 @@ export var moveNode = function moveNode(api) {
290
287
  var isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
291
288
  exposure: true
292
289
  });
290
+ var slicePosition = getSelectedSlicePosition(start, tr, api);
293
291
  if (isMultiSelect) {
294
- var slicePosition = getSelectedSlicePosition(start, tr, api);
295
292
  sliceFrom = slicePosition.from;
296
293
  sliceTo = slicePosition.to;
297
294
  var attributes = getMultiSelectAnalyticsAttributes(tr, sliceFrom, sliceTo);
@@ -1,6 +1,7 @@
1
1
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
2
  import _createClass from "@babel/runtime/helpers/createClass";
3
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
+ import ReactDOM from 'react-dom';
4
5
  import uuid from 'uuid';
5
6
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
6
7
  export var TYPE_DROP_TARGET_DEC = 'drop-target-decoration';
@@ -39,9 +40,6 @@ export var unmountDecorations = function unmountDecorations(nodeViewPortalProvid
39
40
  // as it was more responsive and causes less re-rendering
40
41
  var decorationsToRemove = document.querySelectorAll("[".concat(selector, "=\"true\"]"));
41
42
  decorationsToRemove.forEach(function (el) {
42
- var nodeKey = el.getAttribute(key);
43
- if (nodeKey) {
44
- nodeViewPortalProviderAPI.remove(nodeKey);
45
- }
43
+ ReactDOM.unmountComponentAtNode(el);
46
44
  });
47
45
  };