@atlaskit/editor-plugin-block-controls 2.26.1 → 2.26.2

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 (42) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/cjs/editor-commands/move-node.js +16 -15
  3. package/dist/cjs/editor-commands/move-to-layout.js +20 -8
  4. package/dist/cjs/editor-commands/show-drag-handle.js +89 -3
  5. package/dist/cjs/pm-plugins/decorations-anchor.js +5 -10
  6. package/dist/cjs/pm-plugins/decorations-common.js +5 -1
  7. package/dist/cjs/pm-plugins/main.js +28 -8
  8. package/dist/cjs/pm-plugins/utils/analytics.js +66 -0
  9. package/dist/cjs/pm-plugins/utils/selection.js +22 -2
  10. package/dist/cjs/ui/drag-handle.js +23 -9
  11. package/dist/es2019/editor-commands/move-node.js +17 -16
  12. package/dist/es2019/editor-commands/move-to-layout.js +20 -8
  13. package/dist/es2019/editor-commands/show-drag-handle.js +88 -3
  14. package/dist/es2019/pm-plugins/decorations-anchor.js +6 -11
  15. package/dist/es2019/pm-plugins/decorations-common.js +4 -0
  16. package/dist/es2019/pm-plugins/main.js +24 -6
  17. package/dist/es2019/pm-plugins/utils/{fire-analytics.js → analytics.js} +31 -3
  18. package/dist/es2019/pm-plugins/utils/selection.js +22 -1
  19. package/dist/es2019/ui/drag-handle.js +19 -3
  20. package/dist/esm/editor-commands/move-node.js +17 -16
  21. package/dist/esm/editor-commands/move-to-layout.js +20 -8
  22. package/dist/esm/editor-commands/show-drag-handle.js +88 -2
  23. package/dist/esm/pm-plugins/decorations-anchor.js +6 -11
  24. package/dist/esm/pm-plugins/decorations-common.js +4 -0
  25. package/dist/esm/pm-plugins/main.js +27 -7
  26. package/dist/esm/pm-plugins/utils/{fire-analytics.js → analytics.js} +32 -3
  27. package/dist/esm/pm-plugins/utils/selection.js +21 -1
  28. package/dist/esm/ui/drag-handle.js +22 -4
  29. package/dist/types/editor-commands/show-drag-handle.d.ts +1 -1
  30. package/dist/types/pm-plugins/decorations-common.d.ts +1 -0
  31. package/dist/types/pm-plugins/main.d.ts +1 -0
  32. package/dist/types/pm-plugins/utils/analytics.d.ts +12 -0
  33. package/dist/types/pm-plugins/utils/selection.d.ts +9 -0
  34. package/dist/types-ts4.5/editor-commands/show-drag-handle.d.ts +1 -1
  35. package/dist/types-ts4.5/pm-plugins/decorations-common.d.ts +1 -0
  36. package/dist/types-ts4.5/pm-plugins/main.d.ts +1 -0
  37. package/dist/types-ts4.5/pm-plugins/utils/analytics.d.ts +12 -0
  38. package/dist/types-ts4.5/pm-plugins/utils/selection.d.ts +9 -0
  39. package/package.json +10 -4
  40. package/dist/cjs/pm-plugins/utils/fire-analytics.js +0 -36
  41. package/dist/types/pm-plugins/utils/fire-analytics.d.ts +0 -5
  42. package/dist/types-ts4.5/pm-plugins/utils/fire-analytics.d.ts +0 -5
@@ -14,12 +14,12 @@ import { findTable, isInTable, isTableSelected } from '@atlaskit/editor-tables/u
14
14
  import { fg } from '@atlaskit/platform-feature-flags';
15
15
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
16
16
  import { key } from '../pm-plugins/main';
17
+ import { attachMoveNodeAnalytics, getMultiSelectAnalyticsAttributes } from '../pm-plugins/utils/analytics';
17
18
  import { DIRECTION } from '../pm-plugins/utils/consts';
18
- import { attachMoveNodeAnalytics } from '../pm-plugins/utils/fire-analytics';
19
19
  import { getNestedNodePosition } from '../pm-plugins/utils/getNestedNodePosition';
20
20
  import { selectNode, setCursorPositionAtMovedNode } from '../pm-plugins/utils/getSelection';
21
21
  import { removeFromSource } from '../pm-plugins/utils/remove-from-source';
22
- import { getMultiSelectionIfPosInside } from '../pm-plugins/utils/selection';
22
+ import { getSelectedSlicePosition } from '../pm-plugins/utils/selection';
23
23
  import { getInsertLayoutStep, updateSelection } from '../pm-plugins/utils/update-selection';
24
24
  import { canMoveNodeToIndex, isInsideTable, transformSliceExpandToNestedExpand } from '../pm-plugins/utils/validation';
25
25
 
@@ -259,22 +259,21 @@ export var moveNode = function moveNode(api) {
259
259
  }
260
260
  var sliceFrom = start;
261
261
  var sliceTo;
262
+ var mappedTo;
263
+ var sourceNodeTypes, hasSelectedMultipleNodes;
262
264
  var isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
263
265
  exposure: true
264
266
  });
265
267
  if (isMultiSelect) {
266
- var _handleNode$nodeSize;
267
- var _getMultiSelectionIfP = getMultiSelectionIfPosInside(api, start),
268
- anchor = _getMultiSelectionIfP.anchor,
269
- head = _getMultiSelectionIfP.head;
270
- var inSelection = anchor !== undefined && head !== undefined;
271
- sliceFrom = inSelection ? Math.min(anchor, head) : start;
272
- var handleSize = (_handleNode$nodeSize = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize !== void 0 ? _handleNode$nodeSize : 1;
273
- var handleEnd = sliceFrom + handleSize;
274
- sliceTo = inSelection ? Math.max(anchor, head) : handleEnd;
268
+ var slicePosition = getSelectedSlicePosition(start, tr, api);
269
+ sliceFrom = slicePosition.from;
270
+ sliceTo = slicePosition.to;
271
+ var attributes = getMultiSelectAnalyticsAttributes(tr, sliceFrom, sliceTo);
272
+ hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes;
273
+ sourceNodeTypes = attributes.nodeTypes;
275
274
  } else {
276
- var _handleNode$nodeSize2;
277
- var size = (_handleNode$nodeSize2 = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize2 !== void 0 ? _handleNode$nodeSize2 : 1;
275
+ var _handleNode$nodeSize;
276
+ var size = (_handleNode$nodeSize = handleNode === null || handleNode === void 0 ? void 0 : handleNode.nodeSize) !== null && _handleNode$nodeSize !== void 0 ? _handleNode$nodeSize : 1;
278
277
  sliceTo = sliceFrom + size;
279
278
  }
280
279
  var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
@@ -282,7 +281,6 @@ export var moveNode = function moveNode(api) {
282
281
  nestedExpand = _tr$doc$type$schema$n.nestedExpand;
283
282
  var $to = tr.doc.resolve(to);
284
283
  var $handlePos = tr.doc.resolve(start);
285
- var mappedTo;
286
284
  if (editorExperiment('nested-dnd', true)) {
287
285
  var nodeCopy = tr.doc.slice(sliceFrom, sliceTo, false); // cut the content
288
286
  var destType = $to.node().type;
@@ -338,7 +336,7 @@ export var moveNode = function moveNode(api) {
338
336
  }
339
337
  }
340
338
  if (editorExperiment('advanced_layouts', true)) {
341
- 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);
339
+ 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, sourceNodeTypes, hasSelectedMultipleNodes);
342
340
  } else {
343
341
  var _api$analytics;
344
342
  api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
@@ -346,13 +344,16 @@ export var moveNode = function moveNode(api) {
346
344
  action: ACTION.MOVED,
347
345
  actionSubject: ACTION_SUBJECT.ELEMENT,
348
346
  actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
349
- attributes: _objectSpread({
347
+ attributes: _objectSpread(_objectSpread({
350
348
  nodeDepth: $handlePos.depth,
351
349
  nodeType: handleNode.type.name,
352
350
  destinationNodeDepth: $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.depth,
353
351
  destinationNodeType: $mappedTo === null || $mappedTo === void 0 ? void 0 : $mappedTo.parent.type.name
354
352
  }, fg('platform_editor_element_drag_and_drop_ed_23873') && {
355
353
  inputMethod: inputMethod
354
+ }), isMultiSelect && {
355
+ sourceNodeTypes: sourceNodeTypes,
356
+ hasSelectedMultipleNodes: hasSelectedMultipleNodes
356
357
  })
357
358
  })(tr);
358
359
  }
@@ -4,9 +4,9 @@ import { Fragment, Node as PMNode } from '@atlaskit/editor-prosemirror/model';
4
4
  import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
5
5
  import { fg } from '@atlaskit/platform-feature-flags';
6
6
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
7
+ import { fireInsertLayoutAnalytics, attachMoveNodeAnalytics, getMultiSelectAnalyticsAttributes } from '../pm-plugins/utils/analytics';
7
8
  import { isFragmentOfType, containsNodeOfType } from '../pm-plugins/utils/check-fragment';
8
9
  import { maxLayoutColumnSupported } from '../pm-plugins/utils/consts';
9
- import { fireInsertLayoutAnalytics, attachMoveNodeAnalytics } from '../pm-plugins/utils/fire-analytics';
10
10
  import { removeFromSource } from '../pm-plugins/utils/remove-from-source';
11
11
  import { getMultiSelectionIfPosInside } from '../pm-plugins/utils/selection';
12
12
  import { updateColumnWidths } from '../pm-plugins/utils/update-column-widths';
@@ -41,9 +41,14 @@ var createNewLayout = function createNewLayout(schema, layoutContents) {
41
41
  var moveToExistingLayout = function moveToExistingLayout(toLayout, toLayoutPos, sourceContent, from, to, tr, $originalFrom, $originalTo, api, selectMovedNode) {
42
42
  var isSameLayout = isInSameLayout($originalFrom, $originalTo);
43
43
  var sourceContentEndPos = -1;
44
- if (editorExperiment('platform_editor_element_drag_and_drop_multiselect', true)) {
44
+ var isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true);
45
+ var sourceNodeTypes, hasSelectedMultipleNodes;
46
+ if (isMultiSelect) {
45
47
  if (sourceContent instanceof Fragment) {
46
48
  sourceContentEndPos = from + sourceContent.size;
49
+ var attributes = getMultiSelectAnalyticsAttributes(tr, from, sourceContentEndPos);
50
+ hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes;
51
+ sourceNodeTypes = attributes.nodeTypes;
47
52
  }
48
53
  } else {
49
54
  if (sourceContent instanceof PMNode) {
@@ -62,7 +67,7 @@ var moveToExistingLayout = function moveToExistingLayout(toLayout, toLayoutPos,
62
67
  if (!fg('platform_editor_advanced_layouts_post_fix_patch_1') || selectMovedNode) {
63
68
  tr.setSelection(new NodeSelection(tr.doc.resolve(mappedTo))).scrollIntoView();
64
69
  }
65
- 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);
70
+ 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);
66
71
  } else if (toLayout.childCount < maxLayoutColumnSupported()) {
67
72
  var _$originalFrom$nodeAf2;
68
73
  if (fg('platform_editor_advanced_layouts_post_fix_patch_1')) {
@@ -73,7 +78,7 @@ var moveToExistingLayout = function moveToExistingLayout(toLayout, toLayoutPos,
73
78
  var mappedFrom = tr.mapping.map(from);
74
79
  removeFromSource(tr, tr.doc.resolve(mappedFrom), tr.mapping.map(sourceContentEndPos));
75
80
  }
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);
81
+ 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);
77
82
  }
78
83
  return tr;
79
84
  };
@@ -191,7 +196,7 @@ var canMoveToLayout = function canMoveToLayout(api, from, to, tr, moveNodeAtCurs
191
196
  var _getMultiSelectionIfP = getMultiSelectionIfPosInside(api, from),
192
197
  anchor = _getMultiSelectionIfP.anchor,
193
198
  head = _getMultiSelectionIfP.head;
194
- if (anchor && head) {
199
+ if (anchor !== undefined && head !== undefined) {
195
200
  sourceFrom = Math.min(anchor, head);
196
201
  sourceTo = Math.max(anchor, head);
197
202
  sourceContent = tr.doc.slice(sourceFrom, sourceTo).content;
@@ -248,7 +253,7 @@ var getBreakoutMode = function getBreakoutMode(content, breakout) {
248
253
  var _content$marks$find;
249
254
  return (_content$marks$find = content.marks.find(function (m) {
250
255
  return m.type === breakout;
251
- })) === null || _content$marks$find === void 0 ? void 0 : _content$marks$find.attrs;
256
+ })) === null || _content$marks$find === void 0 ? void 0 : _content$marks$find.attrs.mode;
252
257
  } else if (content instanceof Fragment) {
253
258
  // Find the first breakout mode in the fragment
254
259
  var firstBreakoutMode;
@@ -308,6 +313,7 @@ export var moveToLayout = function moveToLayout(api) {
308
313
  if (!fromContentWithoutBreakout) {
309
314
  return tr;
310
315
  }
316
+ var isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true);
311
317
  if (toNode.type === layoutSection) {
312
318
  var toPos = options !== null && options !== void 0 && options.moveToEnd ? to + toNode.nodeSize - 1 : to + 1;
313
319
  return moveToExistingLayout(toNode, to, fromContentWithoutBreakout, $sourceFrom.pos, toPos, tr, $sourceFrom, $to, api, options === null || options === void 0 ? void 0 : options.selectMovedNode);
@@ -327,7 +333,7 @@ export var moveToLayout = function moveToLayout(api) {
327
333
  // resolve again the source node after node updated (remove breakout marks)
328
334
  toNodeWithoutBreakout = tr.doc.resolve(to).nodeAfter || toNode;
329
335
  }
330
- if (editorExperiment('platform_editor_element_drag_and_drop_multiselect', true)) {
336
+ if (isMultiSelect) {
331
337
  if (isFragmentOfType(fromContentWithoutBreakout, 'layoutColumn') && fromContentWithoutBreakout.firstChild) {
332
338
  fromContentWithoutBreakout = fromContentWithoutBreakout.firstChild.content;
333
339
  }
@@ -339,6 +345,12 @@ export var moveToLayout = function moveToLayout(api) {
339
345
  var layoutContents = options !== null && options !== void 0 && options.moveToEnd ? [toNodeWithoutBreakout, fromContentWithoutBreakout] : [fromContentWithoutBreakout, toNodeWithoutBreakout];
340
346
  var newLayout = createNewLayout(tr.doc.type.schema, layoutContents);
341
347
  if (newLayout) {
348
+ var sourceNodeTypes, hasSelectedMultipleNodes;
349
+ if (isMultiSelect) {
350
+ var attributes = getMultiSelectAnalyticsAttributes(tr, $sourceFrom.pos, sourceTo);
351
+ hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes;
352
+ sourceNodeTypes = attributes.nodeTypes;
353
+ }
342
354
  tr = removeFromSource(tr, $sourceFrom, sourceTo);
343
355
  var mappedTo = tr.mapping.map(to);
344
356
  tr.delete(mappedTo, mappedTo + toNodeWithoutBreakout.nodeSize).insert(mappedTo, newLayout);
@@ -348,7 +360,7 @@ export var moveToLayout = function moveToLayout(api) {
348
360
  breakoutMode && tr.setNodeMarkup(mappedTo, newLayout.type, newLayout.attrs, [breakout.create({
349
361
  mode: breakoutMode
350
362
  })]);
351
- fireInsertLayoutAnalytics(tr, api);
363
+ fireInsertLayoutAnalytics(tr, api, sourceNodeTypes, hasSelectedMultipleNodes);
352
364
  }
353
365
  return tr;
354
366
  }
@@ -1,8 +1,11 @@
1
+ import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
1
2
  import { isInTable } from '@atlaskit/editor-tables/utils';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
2
4
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
3
- import { key } from '../pm-plugins/main';
5
+ import { findNodeDecs } from '../pm-plugins/decorations-anchor';
6
+ import { getDecorations, key } from '../pm-plugins/main';
4
7
  import { getNestedNodePosition } from '../pm-plugins/utils/getNestedNodePosition';
5
- export var showDragHandleAtSelection = function showDragHandleAtSelection(api, shouldFocusParentNode) {
8
+ var showDragHandleAtSelectionOld = function showDragHandleAtSelectionOld(api, shouldFocusParentNode) {
6
9
  return function (state, _, view) {
7
10
  var $from = state.selection.$from;
8
11
  var shouldFocusParentNode;
@@ -62,4 +65,87 @@ export var showDragHandleAtSelection = function showDragHandleAtSelection(api, s
62
65
  }
63
66
  return false;
64
67
  };
68
+ };
69
+ var findParentPosForHandle = function findParentPosForHandle(state) {
70
+ var _activeNode$handleOpt2;
71
+ var $from = state.selection.$from;
72
+ var _ref2 = key.getState(state) || {},
73
+ activeNode = _ref2.activeNode;
74
+
75
+ // if a node handle is already focused, return the parent pos of that node (with focused handle)
76
+ if (activeNode && (_activeNode$handleOpt2 = activeNode.handleOptions) !== null && _activeNode$handleOpt2 !== void 0 && _activeNode$handleOpt2.isFocused) {
77
+ var $activeNodePos = state.doc.resolve(activeNode.pos);
78
+
79
+ // if the handle is at the top level already, do nothing
80
+ if ($activeNodePos.depth === 0) {
81
+ return undefined;
82
+ }
83
+ return $activeNodePos.before();
84
+ }
85
+
86
+ // if we are in second level of nested node, we should focus the node at level 1
87
+ if ($from.depth <= 1) {
88
+ return $from.before(1);
89
+ }
90
+
91
+ // if we are inside a table, we should focus the table's handle
92
+ var parentTableNode = findParentNodeOfType([state.schema.nodes.table])(state.selection);
93
+ if (parentTableNode) {
94
+ return parentTableNode.pos;
95
+ }
96
+
97
+ // else find closest parent node
98
+ return getNestedNodePosition(state);
99
+ };
100
+ var findNextAnchorDecoration = function findNextAnchorDecoration(state) {
101
+ var decorations = getDecorations(state);
102
+ if (!decorations) {
103
+ return undefined;
104
+ }
105
+ var nextHandleNodePos = findParentPosForHandle(state);
106
+ if (nextHandleNodePos === undefined) {
107
+ return undefined;
108
+ }
109
+ var nextHandleNode = state.doc.nodeAt(nextHandleNodePos);
110
+ var nodeDecorations = nextHandleNode && findNodeDecs(decorations, nextHandleNodePos, nextHandleNodePos + nextHandleNode.nodeSize);
111
+ if (!nodeDecorations || nodeDecorations.length === 0) {
112
+ return undefined;
113
+ }
114
+
115
+ // ensure the decoration covers the position of the look up node
116
+ nodeDecorations = nodeDecorations.filter(function (decoration) {
117
+ return decoration.from <= nextHandleNodePos;
118
+ });
119
+ if (nodeDecorations.length === 0) {
120
+ return undefined;
121
+ }
122
+
123
+ // sort the decorations by the position of the node
124
+ // so we can find the closest decoration to the node
125
+ nodeDecorations.sort(function (a, b) {
126
+ if (a.from === b.from) {
127
+ return a.to - b.to;
128
+ }
129
+ return b.from - a.from;
130
+ });
131
+
132
+ // return the closest decoration to the node
133
+ return nodeDecorations[0];
134
+ };
135
+ var showDragHandleAtSelectionNew = function showDragHandleAtSelectionNew(api) {
136
+ return function (state) {
137
+ var decoration = findNextAnchorDecoration(state);
138
+ if (api && decoration) {
139
+ api.core.actions.execute(api.blockControls.commands.showDragHandleAt(decoration.from, decoration.spec.anchorName, decoration.spec.nodeTypeWithLevel, {
140
+ isFocused: true
141
+ }));
142
+ return true;
143
+ }
144
+ return false;
145
+ };
146
+ };
147
+ export var showDragHandleAtSelection = function showDragHandleAtSelection(api) {
148
+ return function (state, dispatch, view) {
149
+ return editorExperiment('nested-dnd', true) && fg('platform_editor_advanced_layouts_a11y') ? showDragHandleAtSelectionNew(api)(state) : showDragHandleAtSelectionOld(api)(state, dispatch, view);
150
+ };
65
151
  };
@@ -2,7 +2,7 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
3
3
  import { fg } from '@atlaskit/platform-feature-flags';
4
4
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
5
- import { getNestedDepth, getNodeAnchor, TYPE_NODE_DEC } from './decorations-common';
5
+ import { getNestedDepth, getNodeAnchor, getNodeTypeWithLevel, TYPE_NODE_DEC } from './decorations-common';
6
6
  var IGNORE_NODES = ['tableCell', 'tableHeader', 'tableRow', 'listItem', 'caption', 'layoutColumn'];
7
7
  var IGNORE_NODES_NEXT = ['tableCell', 'tableHeader', 'tableRow', 'listItem', 'caption'];
8
8
  var IGNORE_NODE_DESCENDANTS = ['listItem', 'taskList', 'decisionList', 'mediaSingle'];
@@ -71,11 +71,10 @@ export var nodeDecorations = function nodeDecorations(newState, from, to) {
71
71
  var ignore_nodes = editorExperiment('advanced_layouts', true) ? IGNORE_NODES_NEXT : IGNORE_NODES;
72
72
  newState.doc.nodesBetween(docFrom, docTo, function (node, pos, parent, index) {
73
73
  var depth = 0;
74
- var anchorName;
75
74
  var shouldDescend = shouldDescendIntoNode(node);
76
- anchorName = getNodeAnchor(node);
75
+ var anchorName = getNodeAnchor(node);
76
+ var nodeTypeWithLevel = getNodeTypeWithLevel(node);
77
77
  if (editorExperiment('nested-dnd', true)) {
78
- var _anchorName;
79
78
  // Doesn't descend into a node
80
79
  if (node.isInline) {
81
80
  return false;
@@ -84,19 +83,15 @@ export var nodeDecorations = function nodeDecorations(newState, from, to) {
84
83
  if (shouldIgnoreNode(node, ignore_nodes, depth, parent)) {
85
84
  return shouldDescend; //skip over, don't consider it a valid depth
86
85
  }
87
- anchorName = (_anchorName = anchorName) !== null && _anchorName !== void 0 ? _anchorName : "--node-anchor-".concat(node.type.name, "-").concat(pos);
88
- } else {
89
- var _anchorName2;
90
- anchorName = (_anchorName2 = anchorName) !== null && _anchorName2 !== void 0 ? _anchorName2 : "--node-anchor-".concat(node.type.name, "-").concat(index);
91
86
  }
92
87
  var anchorStyles = "anchor-name: ".concat(anchorName, ";");
93
- var subType = node.attrs.level ? "-".concat(node.attrs.level) : '';
94
88
  decs.push(Decoration.node(pos, pos + node.nodeSize, _defineProperty(_defineProperty(_defineProperty({
95
89
  style: anchorStyles
96
- }, 'data-drag-handler-anchor-name', anchorName), 'data-drag-handler-node-type', node.type.name + subType), 'data-drag-handler-anchor-depth', "".concat(depth)), {
90
+ }, 'data-drag-handler-anchor-name', anchorName), 'data-drag-handler-node-type', nodeTypeWithLevel), 'data-drag-handler-anchor-depth', "".concat(depth)), {
97
91
  type: TYPE_NODE_DEC,
98
92
  anchorName: anchorName,
99
- nodeType: node.type.name
93
+ nodeType: node.type.name,
94
+ nodeTypeWithLevel: nodeTypeWithLevel
100
95
  }));
101
96
  return shouldDescend && depth < getNestedDepth();
102
97
  });
@@ -13,6 +13,10 @@ export var getNodeAnchor = function getNodeAnchor(node) {
13
13
  var handleId = ObjHash.getForNode(node);
14
14
  return "--node-anchor-".concat(node.type.name, "-").concat(handleId);
15
15
  };
16
+ export var getNodeTypeWithLevel = function getNodeTypeWithLevel(node) {
17
+ var subType = node.attrs.level ? "-".concat(node.attrs.level) : '';
18
+ return node.type.name + subType;
19
+ };
16
20
  var ObjHash = /*#__PURE__*/function () {
17
21
  function ObjHash() {
18
22
  _classCallCheck(this, ObjHash);
@@ -1,4 +1,7 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2
5
  import rafSchedule from 'raf-schd';
3
6
  import { AnalyticsStep } from '@atlaskit/adf-schema/steps';
4
7
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
@@ -19,7 +22,9 @@ import { dropTargetDecorations, findDropTargetDecs } from './decorations-drop-ta
19
22
  import { handleMouseOver } from './handle-mouse-over';
20
23
  import { boundKeydownHandler } from './keymap';
21
24
  import { defaultActiveAnchorTracker } from './utils/active-anchor-tracker';
25
+ import { getMultiSelectAnalyticsAttributes } from './utils/analytics';
22
26
  import { AnchorRectCache, isAnchorSupported } from './utils/anchor-utils';
27
+ import { getSelectedSlicePosition } from './utils/selection';
23
28
  import { getTrMetadata } from './utils/transactions';
24
29
  export var key = new PluginKey('blockControls');
25
30
  var EDITOR_BLOCKS_DRAG_INIT = 'Editor Blocks Drag Initialization Time';
@@ -71,7 +76,8 @@ var destroyFn = function destroyFn(api, editorView) {
71
76
  }
72
77
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref3) {
73
78
  var tr = _ref3.tr;
74
- if (editorExperiment('platform_editor_element_drag_and_drop_multiselect', true)) {
79
+ var isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true);
80
+ if (isMultiSelect) {
75
81
  var _api$blockControls, _api$selection;
76
82
  var _ref4 = (api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
77
83
  multiSelectDnD = _ref4.multiSelectDnD;
@@ -92,6 +98,13 @@ var destroyFn = function destroyFn(api, editorView) {
92
98
  // if no drop targets are rendered, assume that drop is invalid
93
99
  if (location.current.dropTargets.length === 0) {
94
100
  var _api$analytics2;
101
+ var nodeTypes, hasSelectedMultipleNodes;
102
+ if (isMultiSelect && api) {
103
+ var position = getSelectedSlicePosition(start, tr, api);
104
+ var attributes = getMultiSelectAnalyticsAttributes(tr, position.from, position.to);
105
+ nodeTypes = attributes.nodeTypes;
106
+ hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes;
107
+ }
95
108
  var resolvedMovingNode = tr.doc.resolve(start);
96
109
  var maybeNode = resolvedMovingNode.nodeAfter;
97
110
  api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.attachAnalyticsEvent({
@@ -99,10 +112,13 @@ var destroyFn = function destroyFn(api, editorView) {
99
112
  action: ACTION.CANCELLED,
100
113
  actionSubject: ACTION_SUBJECT.DRAG,
101
114
  actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
102
- attributes: {
115
+ attributes: _objectSpread({
103
116
  nodeDepth: resolvedMovingNode.depth,
104
117
  nodeType: (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name) || ''
105
- }
118
+ }, isMultiSelect && {
119
+ nodeTypes: nodeTypes,
120
+ hasSelectedMultipleNodes: hasSelectedMultipleNodes
121
+ })
106
122
  })(tr);
107
123
  }
108
124
  return tr.setMeta(key, {
@@ -127,6 +143,10 @@ var initialState = {
127
143
  isPMDragging: false,
128
144
  multiSelectDnD: undefined
129
145
  };
146
+ export var getDecorations = function getDecorations(state) {
147
+ var _key$getState;
148
+ return (_key$getState = key.getState(state)) === null || _key$getState === void 0 ? void 0 : _key$getState.decorations;
149
+ };
130
150
  export var newApply = function newApply(api, formatMessage, tr, currentState, newState, flags, nodeViewPortalProviderAPI, anchorRectCache) {
131
151
  var _meta$activeNode, _activeNode, _activeNode2, _meta$activeNode$hand, _meta$isDragging, _meta$isDragging2, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging, _meta$multiSelectDnD;
132
152
  var activeNode = currentState.activeNode,
@@ -462,12 +482,12 @@ export var createPlugin = function createPlugin(api, getIntl, nodeViewPortalProv
462
482
  },
463
483
  props: {
464
484
  decorations: function decorations(state) {
465
- var _api$editorDisabled, _key$getState;
485
+ var _api$editorDisabled, _key$getState2;
466
486
  var isDisabled = api === null || api === void 0 || (_api$editorDisabled = api.editorDisabled) === null || _api$editorDisabled === void 0 || (_api$editorDisabled = _api$editorDisabled.sharedState.currentState()) === null || _api$editorDisabled === void 0 ? void 0 : _api$editorDisabled.editorDisabled;
467
487
  if (isDisabled) {
468
488
  return;
469
489
  }
470
- return (_key$getState = key.getState(state)) === null || _key$getState === void 0 ? void 0 : _key$getState.decorations;
490
+ return (_key$getState2 = key.getState(state)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.decorations;
471
491
  },
472
492
  handleDOMEvents: {
473
493
  drop: function drop(view, event) {
@@ -540,10 +560,10 @@ export var createPlugin = function createPlugin(api, getIntl, nodeViewPortalProv
540
560
  }));
541
561
  },
542
562
  dragend: function dragend(view) {
543
- var _key$getState2;
563
+ var _key$getState3;
544
564
  var state = view.state,
545
565
  dispatch = view.dispatch;
546
- if ((_key$getState2 = key.getState(state)) !== null && _key$getState2 !== void 0 && _key$getState2.isPMDragging) {
566
+ if ((_key$getState3 = key.getState(state)) !== null && _key$getState3 !== void 0 && _key$getState3.isPMDragging) {
547
567
  dispatch(state.tr.setMeta(key, {
548
568
  isPMDragging: false
549
569
  }));
@@ -1,5 +1,7 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
- export var attachMoveNodeAnalytics = function attachMoveNodeAnalytics(tr, inputMethod, fromDepth, fromNodeType, toDepth, toNodeType, isSameParent, api) {
3
+ import { fg } from '@atlaskit/platform-feature-flags';
4
+ export var attachMoveNodeAnalytics = function attachMoveNodeAnalytics(tr, inputMethod, fromDepth, fromNodeType, toDepth, toNodeType, isSameParent, api, fromNodeTypes, hasSelectedMultipleNodes) {
3
5
  var _api$analytics;
4
6
  return api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 ? void 0 : _api$analytics.attachAnalyticsEvent({
5
7
  eventType: EVENT_TYPE.TRACK,
@@ -9,6 +11,8 @@ export var attachMoveNodeAnalytics = function attachMoveNodeAnalytics(tr, inputM
9
11
  attributes: {
10
12
  nodeDepth: fromDepth,
11
13
  nodeType: fromNodeType,
14
+ nodeTypes: fromNodeTypes,
15
+ hasSelectedMultipleNodes: hasSelectedMultipleNodes,
12
16
  destinationNodeDepth: toDepth,
13
17
  destinationNodeType: toNodeType,
14
18
  isSameParent: isSameParent,
@@ -16,15 +20,40 @@ export var attachMoveNodeAnalytics = function attachMoveNodeAnalytics(tr, inputM
16
20
  }
17
21
  })(tr);
18
22
  };
19
- export var fireInsertLayoutAnalytics = function fireInsertLayoutAnalytics(tr, api) {
23
+ export var fireInsertLayoutAnalytics = function fireInsertLayoutAnalytics(tr, api, nodeTypes, hasSelectedMultipleNodes) {
20
24
  var _api$analytics2;
21
25
  api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || (_api$analytics2 = _api$analytics2.actions) === null || _api$analytics2 === void 0 || _api$analytics2.attachAnalyticsEvent({
22
26
  action: ACTION.INSERTED,
23
27
  actionSubject: ACTION_SUBJECT.DOCUMENT,
24
28
  actionSubjectId: ACTION_SUBJECT_ID.LAYOUT,
25
29
  attributes: {
26
- inputMethod: INPUT_METHOD.DRAG_AND_DROP
30
+ inputMethod: INPUT_METHOD.DRAG_AND_DROP,
31
+ nodeTypes: nodeTypes,
32
+ hasSelectedMultipleNodes: hasSelectedMultipleNodes
27
33
  },
28
34
  eventType: EVENT_TYPE.TRACK
29
35
  })(tr);
36
+ };
37
+
38
+ /**
39
+ * Given a range, return distinctive types of node and whether there are multiple nodes in the range
40
+ */
41
+ export var getMultiSelectAnalyticsAttributes = function getMultiSelectAnalyticsAttributes(tr, anchor, head) {
42
+ var nodeTypes = [];
43
+ var from = Math.min(anchor, head);
44
+ var to = Math.max(anchor, head);
45
+ tr.doc.nodesBetween(from, to, function (node, pos) {
46
+ if (pos < from) {
47
+ // ignore parent node
48
+ return true;
49
+ }
50
+ nodeTypes.push(node.type.name);
51
+
52
+ // only care about the top level (relatively in the range) nodes
53
+ return false;
54
+ });
55
+ return {
56
+ nodeTypes: fg('platform_editor_track_node_types') ? _toConsumableArray(new Set(nodeTypes)).sort().join(',') : undefined,
57
+ hasSelectedMultipleNodes: nodeTypes.length > 1
58
+ };
30
59
  };
@@ -1,6 +1,6 @@
1
1
  export var getMultiSelectionIfPosInside = function getMultiSelectionIfPosInside(api, pos) {
2
2
  var _api$blockControls;
3
- var _ref = (api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
3
+ var _ref = ((_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
4
4
  multiSelectDnD = _ref.multiSelectDnD;
5
5
  if (multiSelectDnD && multiSelectDnD.anchor >= 0 && multiSelectDnD.head >= 0) {
6
6
  var multiFrom = Math.min(multiSelectDnD.anchor, multiSelectDnD.head);
@@ -13,4 +13,24 @@ export var getMultiSelectionIfPosInside = function getMultiSelectionIfPosInside(
13
13
  } : {};
14
14
  }
15
15
  return {};
16
+ };
17
+
18
+ /**
19
+ *
20
+ * @returns from and to positions of the selected content (after expansion)
21
+ */
22
+ export var getSelectedSlicePosition = function getSelectedSlicePosition(handlePos, tr, api) {
23
+ var _activeNode$nodeSize;
24
+ var _getMultiSelectionIfP = getMultiSelectionIfPosInside(api, handlePos),
25
+ anchor = _getMultiSelectionIfP.anchor,
26
+ head = _getMultiSelectionIfP.head;
27
+ var inSelection = anchor !== undefined && head !== undefined;
28
+ var from = inSelection ? Math.min(anchor, head) : handlePos;
29
+ var activeNode = tr.doc.nodeAt(handlePos);
30
+ var activeNodeEndPos = handlePos + ((_activeNode$nodeSize = activeNode === null || activeNode === void 0 ? void 0 : activeNode.nodeSize) !== null && _activeNode$nodeSize !== void 0 ? _activeNode$nodeSize : 1);
31
+ var to = inSelection ? Math.max(anchor, head) : activeNodeEndPos;
32
+ return {
33
+ from: from,
34
+ to: to
35
+ };
16
36
  };
@@ -1,5 +1,8 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
3
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
4
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
5
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3
6
  /**
4
7
  * @jsxRuntime classic
5
8
  * @jsx jsx
@@ -23,6 +26,7 @@ import { Box, xcss } from '@atlaskit/primitives';
23
26
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
24
27
  import Tooltip from '@atlaskit/tooltip';
25
28
  import { key } from '../pm-plugins/main';
29
+ import { getMultiSelectAnalyticsAttributes } from '../pm-plugins/utils/analytics';
26
30
  import { getLeftPosition, getTopPosition } from '../pm-plugins/utils/drag-handle-positions';
27
31
  import { getNestedNodePosition } from '../pm-plugins/utils/getNestedNodePosition';
28
32
  import { isHandleInSelection, selectNode } from '../pm-plugins/utils/getSelection';
@@ -254,7 +258,11 @@ export var DragHandle = function DragHandle(_ref) {
254
258
  var isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true, {
255
259
  exposure: true
256
260
  });
261
+ var nodeTypes, hasSelectedMultipleNodes;
262
+ var resolvedMovingNode = tr.doc.resolve(start);
263
+ var maybeNode = resolvedMovingNode.nodeAfter;
257
264
  if (isMultiSelect) {
265
+ var _tr$getMeta;
258
266
  var handlePos = getPos();
259
267
  if (typeof handlePos !== 'number') {
260
268
  return tr;
@@ -265,22 +273,32 @@ export var DragHandle = function DragHandle(_ref) {
265
273
  tr: tr
266
274
  });
267
275
  }
276
+ var multiSelectDnD = (_tr$getMeta = tr.getMeta(key)) === null || _tr$getMeta === void 0 ? void 0 : _tr$getMeta.multiSelectDnD;
277
+ if (multiSelectDnD) {
278
+ var attributes = getMultiSelectAnalyticsAttributes(tr, multiSelectDnD.anchor, multiSelectDnD.head);
279
+ nodeTypes = attributes.nodeTypes;
280
+ hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes;
281
+ } else {
282
+ nodeTypes = maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name;
283
+ hasSelectedMultipleNodes = false;
284
+ }
268
285
  }
269
286
  api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.setNodeDragged(getPos, anchorName, nodeType)({
270
287
  tr: tr
271
288
  });
272
- var resolvedMovingNode = tr.doc.resolve(start);
273
- var maybeNode = resolvedMovingNode.nodeAfter;
274
289
  tr.setMeta('scrollIntoView', false);
275
290
  api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.attachAnalyticsEvent({
276
291
  eventType: EVENT_TYPE.UI,
277
292
  action: ACTION.DRAGGED,
278
293
  actionSubject: ACTION_SUBJECT.ELEMENT,
279
294
  actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
280
- attributes: {
295
+ attributes: _objectSpread({
281
296
  nodeDepth: resolvedMovingNode.depth,
282
297
  nodeType: (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name) || ''
283
- }
298
+ }, isMultiSelect && {
299
+ nodeTypes: nodeTypes,
300
+ hasSelectedMultipleNodes: hasSelectedMultipleNodes
301
+ })
284
302
  })(tr);
285
303
  return tr;
286
304
  });
@@ -1,3 +1,3 @@
1
1
  import type { Command, ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
2
  import type { BlockControlsPlugin } from '../blockControlsPluginType';
3
- export declare const showDragHandleAtSelection: (api?: ExtractInjectionAPI<BlockControlsPlugin>, shouldFocusParentNode?: boolean) => Command;
3
+ export declare const showDragHandleAtSelection: (api?: ExtractInjectionAPI<BlockControlsPlugin>) => Command;
@@ -5,4 +5,5 @@ export declare const TYPE_HANDLE_DEC = "drag-handle";
5
5
  export declare const TYPE_NODE_DEC = "node-decoration";
6
6
  export declare const getNestedDepth: () => 0 | 100;
7
7
  export declare const getNodeAnchor: (node: PMNode) => string;
8
+ export declare const getNodeTypeWithLevel: (node: PMNode) => string;
8
9
  export declare const unmountDecorations: (nodeViewPortalProviderAPI: PortalProviderAPI, selector: string, key: string) => void;
@@ -12,6 +12,7 @@ export interface FlagType {
12
12
  isNestedEnabled: boolean;
13
13
  isMultiSelectEnabled: boolean;
14
14
  }
15
+ export declare const getDecorations: (state: EditorState) => DecorationSet | undefined;
15
16
  export declare const newApply: (api: ExtractInjectionAPI<BlockControlsPlugin> | undefined, formatMessage: IntlShape['formatMessage'], tr: ReadonlyTransaction, currentState: PluginState, newState: EditorState, flags: FlagType, nodeViewPortalProviderAPI: PortalProviderAPI, anchorRectCache?: AnchorRectCache) => {
16
17
  decorations: DecorationSet;
17
18
  activeNode: any;
@@ -0,0 +1,12 @@
1
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
+ import { type Transaction } from '@atlaskit/editor-prosemirror/state';
3
+ import { type BlockControlsPlugin } from '../../blockControlsPluginType';
4
+ export declare const attachMoveNodeAnalytics: (tr: Transaction, inputMethod: string, fromDepth: number, fromNodeType: string, toDepth?: number, toNodeType?: string, isSameParent?: boolean, api?: ExtractInjectionAPI<BlockControlsPlugin>, fromNodeTypes?: string, hasSelectedMultipleNodes?: boolean) => boolean | undefined;
5
+ export declare const fireInsertLayoutAnalytics: (tr: Transaction, api?: ExtractInjectionAPI<BlockControlsPlugin>, nodeTypes?: string, hasSelectedMultipleNodes?: boolean) => void;
6
+ /**
7
+ * Given a range, return distinctive types of node and whether there are multiple nodes in the range
8
+ */
9
+ export declare const getMultiSelectAnalyticsAttributes: (tr: Transaction, anchor: number, head: number) => {
10
+ nodeTypes: string | undefined;
11
+ hasSelectedMultipleNodes: boolean;
12
+ };