@atlaskit/editor-plugin-block-controls 2.27.0 → 2.27.4

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 (46) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/cjs/blockControlsPlugin.js +35 -6
  3. package/dist/cjs/pm-plugins/decorations-drop-target.js +11 -5
  4. package/dist/cjs/pm-plugins/main.js +2 -1
  5. package/dist/cjs/pm-plugins/utils/getSelection.js +2 -2
  6. package/dist/cjs/pm-plugins/utils/validation.js +2 -1
  7. package/dist/cjs/ui/block-menu-items.js +103 -0
  8. package/dist/cjs/ui/block-menu.js +77 -0
  9. package/dist/cjs/ui/consts.js +101 -2
  10. package/dist/cjs/ui/drag-handle.js +147 -41
  11. package/dist/cjs/ui/drag-preview.js +83 -34
  12. package/dist/es2019/blockControlsPlugin.js +34 -3
  13. package/dist/es2019/pm-plugins/decorations-drop-target.js +12 -5
  14. package/dist/es2019/pm-plugins/main.js +2 -1
  15. package/dist/es2019/pm-plugins/utils/getSelection.js +1 -1
  16. package/dist/es2019/pm-plugins/utils/validation.js +2 -1
  17. package/dist/es2019/ui/block-menu-items.js +92 -0
  18. package/dist/es2019/ui/block-menu.js +75 -0
  19. package/dist/es2019/ui/consts.js +100 -1
  20. package/dist/es2019/ui/drag-handle.js +152 -40
  21. package/dist/es2019/ui/drag-preview.js +83 -34
  22. package/dist/esm/blockControlsPlugin.js +35 -6
  23. package/dist/esm/pm-plugins/decorations-drop-target.js +11 -5
  24. package/dist/esm/pm-plugins/main.js +2 -1
  25. package/dist/esm/pm-plugins/utils/getSelection.js +1 -1
  26. package/dist/esm/pm-plugins/utils/validation.js +2 -1
  27. package/dist/esm/ui/block-menu-items.js +92 -0
  28. package/dist/esm/ui/block-menu.js +70 -0
  29. package/dist/esm/ui/consts.js +100 -1
  30. package/dist/esm/ui/drag-handle.js +149 -43
  31. package/dist/esm/ui/drag-preview.js +82 -34
  32. package/dist/types/blockControlsPluginType.d.ts +3 -0
  33. package/dist/types/pm-plugins/utils/getSelection.d.ts +3 -3
  34. package/dist/types/pm-plugins/utils/validation.d.ts +1 -1
  35. package/dist/types/ui/block-menu-items.d.ts +17 -0
  36. package/dist/types/ui/block-menu.d.ts +16 -0
  37. package/dist/types/ui/consts.d.ts +7 -0
  38. package/dist/types/ui/drag-preview.d.ts +9 -1
  39. package/dist/types-ts4.5/blockControlsPluginType.d.ts +3 -0
  40. package/dist/types-ts4.5/pm-plugins/utils/getSelection.d.ts +3 -3
  41. package/dist/types-ts4.5/pm-plugins/utils/validation.d.ts +1 -1
  42. package/dist/types-ts4.5/ui/block-menu-items.d.ts +17 -0
  43. package/dist/types-ts4.5/ui/block-menu.d.ts +16 -0
  44. package/dist/types-ts4.5/ui/consts.d.ts +7 -0
  45. package/dist/types-ts4.5/ui/drag-preview.d.ts +9 -1
  46. package/package.json +5 -5
@@ -18,6 +18,7 @@ var _keymaps = require("@atlaskit/editor-common/keymaps");
18
18
  var _messages = require("@atlaskit/editor-common/messages");
19
19
  var _useSharedPluginStateSelector = require("@atlaskit/editor-common/use-shared-plugin-state-selector");
20
20
  var _state = require("@atlaskit/editor-prosemirror/state");
21
+ var _utils = require("@atlaskit/editor-prosemirror/utils");
21
22
  var _dragHandler = _interopRequireDefault(require("@atlaskit/icon/glyph/drag-handler"));
22
23
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
23
24
  var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
@@ -28,7 +29,6 @@ var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
28
29
  var _main = require("../pm-plugins/main");
29
30
  var _analytics2 = require("../pm-plugins/utils/analytics");
30
31
  var _dragHandlePositions = require("../pm-plugins/utils/drag-handle-positions");
31
- var _getNestedNodePosition = require("../pm-plugins/utils/getNestedNodePosition");
32
32
  var _getSelection = require("../pm-plugins/utils/getSelection");
33
33
  var _consts = require("./consts");
34
34
  var _dragPreview = require("./drag-preview");
@@ -106,6 +106,16 @@ var handleIconDragStart = function handleIconDragStart(e) {
106
106
  (_e$target$closest = e.target.closest('button')) === null || _e$target$closest === void 0 || _e$target$closest.dispatchEvent(dragEvent);
107
107
  }
108
108
  };
109
+ var getNodeSpacingForPreview = function getNodeSpacingForPreview(node) {
110
+ if (!node) {
111
+ return _consts.spacingBetweenNodesForPreview['default'];
112
+ }
113
+ var nodeTypeName = node.type.name;
114
+ if (nodeTypeName === 'heading') {
115
+ return _consts.spacingBetweenNodesForPreview["heading".concat(node.attrs.level)] || _consts.spacingBetweenNodesForPreview['default'];
116
+ }
117
+ return _consts.spacingBetweenNodesForPreview[nodeTypeName] || _consts.spacingBetweenNodesForPreview['default'];
118
+ };
109
119
  var DragHandle = exports.DragHandle = function DragHandle(_ref) {
110
120
  var _api$core2, _api$analytics2, _api$core4;
111
121
  var view = _ref.view,
@@ -131,6 +141,9 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
131
141
  featureFlagsState = _useSharedPluginState.featureFlagsState;
132
142
  var selection = (0, _useSharedPluginStateSelector.useSharedPluginStateSelector)(api, 'selection.selection');
133
143
  var isLayoutColumn = nodeType === 'layoutColumn';
144
+ var isMultiSelect = (0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true, {
145
+ exposure: true
146
+ });
134
147
  (0, _react.useEffect)(function () {
135
148
  // blockCard/datasource width is rendered correctly after this decoraton does. We need to observe for changes.
136
149
  if (nodeType === 'blockCard') {
@@ -175,7 +188,14 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
175
188
  return tr;
176
189
  });
177
190
  view.focus();
178
- }, [dragHandleSelected, api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions, api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions, view, getPos, nodeType]);
191
+ if ((0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) {
192
+ var startPos = getPos();
193
+ if (startPos === undefined) {
194
+ return false;
195
+ }
196
+ api === null || api === void 0 || api.core.actions.execute(api.blockControls.commands.toggleBlockMenu());
197
+ }
198
+ }, [dragHandleSelected, api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions, api === null || api === 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]);
179
199
 
180
200
  // TODO - This needs to be investigated further. Drag preview generation is not always working
181
201
  // as expected with a node selection. This workaround sets the selection to the node on mouseDown,
@@ -239,56 +259,140 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
239
259
  };
240
260
  },
241
261
  onGenerateDragPreview: function onGenerateDragPreview(_ref4) {
262
+ var _api$blockControls2;
242
263
  var nativeSetDragImage = _ref4.nativeSetDragImage;
264
+ if (isMultiSelect) {
265
+ var _api$core5;
266
+ api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref5) {
267
+ var tr = _ref5.tr;
268
+ var handlePos = getPos();
269
+ if (typeof handlePos !== 'number') {
270
+ return tr;
271
+ }
272
+ if (!tr.selection.empty && handlePos >= tr.selection.$from.start() - 1 && handlePos <= tr.selection.to) {
273
+ var _api$blockControls;
274
+ api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.setMultiSelectPositions()({
275
+ tr: tr
276
+ });
277
+ }
278
+ return tr;
279
+ });
280
+ }
281
+ var startPos = getPos();
282
+ var state = view.state;
283
+ var doc = state.doc,
284
+ selection = state.selection;
285
+ var _ref6 = (api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.sharedState.currentState()) || {},
286
+ multiSelectDnD = _ref6.multiSelectDnD;
287
+ var sliceFrom = selection.from;
288
+ var sliceTo = selection.to;
289
+ if (multiSelectDnD) {
290
+ var anchor = multiSelectDnD.anchor,
291
+ head = multiSelectDnD.head;
292
+ sliceFrom = Math.min(anchor, head);
293
+ sliceTo = Math.max(anchor, head);
294
+ }
295
+ var expandedSlice = doc.slice(sliceFrom, sliceTo);
296
+ var isDraggingMultiLine = isMultiSelect && startPos !== undefined && startPos >= sliceFrom && startPos <= sliceTo && expandedSlice.content.childCount > 1;
243
297
  (0, _setCustomNativeDragPreview.setCustomNativeDragPreview)({
244
- render: function render(_ref5) {
245
- var container = _ref5.container;
298
+ getOffset: function getOffset() {
299
+ if (!isDraggingMultiLine) {
300
+ return {
301
+ x: 0,
302
+ y: 0
303
+ };
304
+ } else {
305
+ // Calculate the offset of the preview container,
306
+ // So when drag multiple nodes, the preview align with the position of the selected nodes
307
+ var domAtPos = view.domAtPos.bind(view);
308
+ var domElementsHeightBeforeHandle = 0;
309
+ var nodesStartPos = [];
310
+ var nodesEndPos = [];
311
+ var activeNodeMarginTop = 0;
312
+ for (var i = 0; i < expandedSlice.content.childCount; i++) {
313
+ if (i === 0) {
314
+ var _expandedSlice$conten;
315
+ nodesStartPos[i] = sliceFrom;
316
+ nodesEndPos[i] = sliceFrom + (((_expandedSlice$conten = expandedSlice.content.maybeChild(i)) === null || _expandedSlice$conten === void 0 ? void 0 : _expandedSlice$conten.nodeSize) || 0);
317
+ } else {
318
+ var _expandedSlice$conten2;
319
+ nodesStartPos[i] = nodesEndPos[i - 1];
320
+ nodesEndPos[i] = nodesStartPos[i] + (((_expandedSlice$conten2 = expandedSlice.content.maybeChild(i)) === null || _expandedSlice$conten2 === void 0 ? void 0 : _expandedSlice$conten2.nodeSize) || 0);
321
+ }
322
+
323
+ // when the node is before the handle, calculate the height of the node
324
+ if (nodesEndPos[i] <= startPos) {
325
+ // eslint-disable-next-line @atlaskit/editor/no-as-casting
326
+ var currentNodeElement = (0, _utils.findDomRefAtPos)(nodesStartPos[i], domAtPos);
327
+ var maybeCurrentNode = expandedSlice.content.maybeChild(i);
328
+ var currentNodeSpacing = maybeCurrentNode ? _consts.nodeMargins[maybeCurrentNode.type.name].top + _consts.nodeMargins[maybeCurrentNode.type.name].bottom : 0;
329
+ domElementsHeightBeforeHandle = domElementsHeightBeforeHandle + currentNodeElement.offsetHeight + currentNodeSpacing;
330
+ } else {
331
+ // when the node is after the handle, calculate the top margin of the active node
332
+ var maybeNextNode = expandedSlice.content.maybeChild(i);
333
+ activeNodeMarginTop = maybeNextNode ? _consts.nodeMargins[maybeNextNode.type.name].top : 0;
334
+ break;
335
+ }
336
+ }
337
+ return {
338
+ x: 0,
339
+ y: domElementsHeightBeforeHandle + activeNodeMarginTop
340
+ };
341
+ }
342
+ },
343
+ render: function render(_ref7) {
344
+ var container = _ref7.container;
246
345
  var dom = view.dom.querySelector("[data-drag-handler-anchor-name=\"".concat(anchorName, "\"]"));
247
346
  if (!dom) {
248
347
  return;
249
348
  }
250
- return (0, _dragPreview.dragPreview)(container, dom, nodeType);
349
+ if (!isDraggingMultiLine) {
350
+ return (0, _dragPreview.dragPreview)(container, {
351
+ dom: dom,
352
+ nodeType: nodeType
353
+ });
354
+ } else {
355
+ var domAtPos = view.domAtPos.bind(view);
356
+ var previewContent = [];
357
+ expandedSlice.content.descendants(function (node, pos, parent, index) {
358
+ // Get the dom element of the node
359
+ //eslint-disable-next-line @atlaskit/editor/no-as-casting
360
+ var nodeDomElement = (0, _utils.findDomRefAtPos)(sliceFrom + pos, domAtPos);
361
+ var currentNodeSpacing = getNodeSpacingForPreview(node);
362
+ previewContent.push({
363
+ dom: nodeDomElement,
364
+ nodeType: node.type.name,
365
+ nodeSpacing: currentNodeSpacing
366
+ });
367
+ return false; // Only iterate through the first level of nodes
368
+ });
369
+ return (0, _dragPreview.dragPreview)(container, previewContent);
370
+ }
251
371
  },
252
372
  nativeSetDragImage: nativeSetDragImage
253
373
  });
254
374
  },
255
375
  onDragStart: function onDragStart() {
256
- var _api$core5;
376
+ var _api$core6;
257
377
  if (start === undefined) {
258
378
  return;
259
379
  }
260
- api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref6) {
261
- var _api$blockControls2, _api$analytics3;
262
- var tr = _ref6.tr;
263
- var isMultiSelect = (0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true, {
264
- exposure: true
265
- });
380
+ api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 || _api$core6.actions.execute(function (_ref8) {
381
+ var _tr$getMeta, _api$blockControls3, _api$analytics3;
382
+ var tr = _ref8.tr;
266
383
  var nodeTypes, hasSelectedMultipleNodes;
267
384
  var resolvedMovingNode = tr.doc.resolve(start);
268
385
  var maybeNode = resolvedMovingNode.nodeAfter;
269
- if (isMultiSelect) {
270
- var _tr$getMeta;
271
- var handlePos = getPos();
272
- if (typeof handlePos !== 'number') {
273
- return tr;
274
- }
275
- if (!tr.selection.empty && handlePos >= tr.selection.$from.start() - 1 && handlePos <= tr.selection.to) {
276
- var _api$blockControls;
277
- api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.setMultiSelectPositions()({
278
- tr: tr
279
- });
280
- }
281
- var multiSelectDnD = (_tr$getMeta = tr.getMeta(_main.key)) === null || _tr$getMeta === void 0 ? void 0 : _tr$getMeta.multiSelectDnD;
282
- if (multiSelectDnD) {
283
- var attributes = (0, _analytics2.getMultiSelectAnalyticsAttributes)(tr, multiSelectDnD.anchor, multiSelectDnD.head);
284
- nodeTypes = attributes.nodeTypes;
285
- hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes;
286
- } else {
287
- nodeTypes = maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name;
288
- hasSelectedMultipleNodes = false;
289
- }
386
+ var multiSelectDnD = (_tr$getMeta = tr.getMeta(_main.key)) === null || _tr$getMeta === void 0 ? void 0 : _tr$getMeta.multiSelectDnD;
387
+ if (multiSelectDnD) {
388
+ var attributes = (0, _analytics2.getMultiSelectAnalyticsAttributes)(tr, multiSelectDnD.anchor, multiSelectDnD.head);
389
+ nodeTypes = attributes.nodeTypes;
390
+ hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes;
391
+ } else {
392
+ nodeTypes = maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name;
393
+ hasSelectedMultipleNodes = false;
290
394
  }
291
- api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.setNodeDragged(getPos, anchorName, nodeType)({
395
+ api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || _api$blockControls3.commands.setNodeDragged(getPos, anchorName, nodeType)({
292
396
  tr: tr
293
397
  });
294
398
  tr.setMeta('scrollIntoView', false);
@@ -310,7 +414,7 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
310
414
  view.focus();
311
415
  }
312
416
  });
313
- }, [anchorName, api, getPos, nodeType, start, view]);
417
+ }, [anchorName, api, getPos, isMultiSelect, nodeType, start, view]);
314
418
  var macroInteractionUpdates = featureFlagsState === null || featureFlagsState === void 0 ? void 0 : featureFlagsState.macroInteractionUpdates;
315
419
  var calculatePosition = (0, _react.useCallback)(function () {
316
420
  var parentNodeType;
@@ -395,14 +499,11 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
395
499
  }
396
500
  }, [buttonRef, handleOptions === null || handleOptions === void 0 ? void 0 : handleOptions.isFocused, view]);
397
501
  (0, _react.useEffect)(function () {
398
- var isMultiSelect = (0, _experiments.editorExperiment)('platform_editor_element_drag_and_drop_multiselect', true, {
399
- exposure: true
400
- });
401
502
  if (!isMultiSelect || typeof start !== 'number' || !selection) {
402
503
  return;
403
504
  }
404
- setDragHandleSelected((0, _getSelection.isHandleInSelection)(view.state, selection, start));
405
- }, [start, selection, view.state]);
505
+ setDragHandleSelected((0, _getSelection.isHandleCorrelatedToSelection)(view.state, selection, start));
506
+ }, [start, selection, view.state, isMultiSelect]);
406
507
  var helpDescriptors = isTopLevelNode && (0, _platformFeatureFlags.fg)('platform_editor_advanced_layouts_accessibility') ? [{
407
508
  description: formatMessage(_messages.blockControlsMessages.dragToMove)
408
509
  }, {
@@ -428,7 +529,12 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
428
529
  }];
429
530
  var isParentNodeOfTypeLayout;
430
531
  if (!isTopLevelNode && ((0, _platformFeatureFlags.fg)('platform_editor_advanced_layouts_accessibility') || handleOptions !== null && handleOptions !== void 0 && handleOptions.isFocused) && (0, _experiments.editorExperiment)('nested-dnd', true)) {
431
- isParentNodeOfTypeLayout = nodeType === 'layoutSection' || view.state.doc.resolve((0, _getNestedNodePosition.getNestedNodePosition)(view.state)).node().type.name === 'layoutColumn';
532
+ var pos = getPos();
533
+ if (typeof pos === 'number') {
534
+ var _$pos$parent;
535
+ var $pos = view.state.doc.resolve(pos);
536
+ isParentNodeOfTypeLayout = ($pos === null || $pos === void 0 || (_$pos$parent = $pos.parent) === null || _$pos$parent === void 0 ? void 0 : _$pos$parent.type.name) === 'layoutColumn';
537
+ }
432
538
  if (isParentNodeOfTypeLayout) {
433
539
  helpDescriptors = [].concat((0, _toConsumableArray2.default)(helpDescriptors), [{
434
540
  description: formatMessage(_messages.blockControlsMessages.moveLeft),
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.dragPreview = void 0;
8
+ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
7
9
  var _browser = require("@atlaskit/editor-common/browser");
8
10
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
9
11
  var _colors = require("@atlaskit/theme/colors");
@@ -21,14 +23,8 @@ var previewStyleOld = {
21
23
  borderWidth: "var(--ds-border-width-outline, 2px)",
22
24
  backgroundColor: "var(--ds-blanket-selected, #388BFF14)"
23
25
  };
24
- var dragPreview = exports.dragPreview = function dragPreview(container, dom, nodeType) {
26
+ var getPreviewContainerDimensionsForSingle = function getPreviewContainerDimensionsForSingle(dom, nodeType) {
25
27
  var nodeContainer = dom;
26
- container.style.pointerEvents = 'none';
27
- var parent = document.createElement('div');
28
- // ProseMirror class is required to make sure the cloned dom is styled correctly
29
- parent.classList.add('ProseMirror', 'block-ctrl-drag-preview');
30
- var embedCard = dom.querySelector('.embedCardView-content-wrap');
31
- var shouldBeGenericPreview = nodeType === 'embedCard' || nodeType === 'extension' || !!embedCard;
32
28
  if ((0, _platformFeatureFlags.fg)('platform_editor_elements_drag_and_drop_ed_23189')) {
33
29
  var iframeContainer = dom.querySelector('iframe');
34
30
  if (nodeType === 'embedCard') {
@@ -36,41 +32,94 @@ var dragPreview = exports.dragPreview = function dragPreview(container, dom, nod
36
32
  } else if (nodeType === 'extension' && iframeContainer) {
37
33
  nodeContainer = iframeContainer;
38
34
  }
39
- shouldBeGenericPreview = nodeType === 'embedCard' || !!embedCard || nodeType === 'extension' && !!iframeContainer;
40
35
  }
41
36
  var nodeContainerRect = nodeContainer.getBoundingClientRect();
42
- container.style.width = "".concat(nodeContainerRect.width, "px");
43
- container.style.height = "".concat(nodeContainerRect.height, "px");
37
+ return {
38
+ width: nodeContainerRect.width,
39
+ height: nodeContainerRect.height
40
+ };
41
+ };
42
+ var getPreviewContainerDimensions = function getPreviewContainerDimensions(dragPreviewContent) {
43
+ var maxWidth = 0;
44
+ var heightSum = 0;
45
+ for (var index = 0; index < dragPreviewContent.length; index++) {
46
+ var element = dragPreviewContent[index];
47
+ var _getPreviewContainerD = getPreviewContainerDimensionsForSingle(element.dom, element.nodeType),
48
+ width = _getPreviewContainerD.width,
49
+ height = _getPreviewContainerD.height;
50
+ if (width > maxWidth) {
51
+ maxWidth = width;
52
+ }
53
+ heightSum += height;
54
+ }
55
+ return {
56
+ width: maxWidth,
57
+ height: heightSum
58
+ };
59
+ };
60
+ var createGenericPreview = function createGenericPreview() {
61
+ var generalPreview = document.createElement('div');
62
+ // ProseMirror class is required to make sure the cloned dom is styled correctly
63
+ generalPreview.classList.add('ProseMirror', 'block-ctrl-drag-preview');
44
64
  var previewStyle = (0, _platformFeatureFlags.fg)('platform_editor_elements_drag_and_drop_ed_23189') ? previewStyleNew : previewStyleOld;
65
+ generalPreview.style.border = "".concat(previewStyle.borderWidth, " ").concat(previewStyle.borderStyle, " ").concat(previewStyle.borderColor);
66
+ generalPreview.style.borderRadius = previewStyle.borderRadius;
67
+ generalPreview.style.backgroundColor = previewStyle.backgroundColor;
68
+ generalPreview.style.height = '100%';
69
+ generalPreview.setAttribute('data-testid', 'block-ctrl-generic-drag-preview');
70
+ return generalPreview;
71
+ };
72
+ var createContentPreviewElement = function createContentPreviewElement(dom, nodeType, nodeSpacing) {
73
+ var contentPreviewOneElement = document.createElement('div');
74
+ contentPreviewOneElement.classList.add('ProseMirror', 'block-ctrl-drag-preview');
75
+ var resizer = dom.querySelector('.resizer-item');
76
+ var clonedDom = resizer && ['mediaSingle', 'table'].includes(nodeType) ?
77
+ // Ignored via go/ees005
78
+ // eslint-disable-next-line @atlaskit/editor/no-as-casting
79
+ resizer.cloneNode(true) :
80
+ // Ignored via go/ees005
81
+ // eslint-disable-next-line @atlaskit/editor/no-as-casting
82
+ dom.cloneNode(true);
83
+ clonedDom.style.marginLeft = '0';
84
+ clonedDom.style.marginTop = nodeSpacing ? "".concat(nodeSpacing.top) : '0';
85
+ clonedDom.style.marginRight = '0';
86
+ clonedDom.style.marginBottom = nodeSpacing ? "".concat(nodeSpacing.bottom) : '0';
87
+ clonedDom.style.boxShadow = 'none';
88
+ clonedDom.style.opacity = _browser.browser.windows ? '1' : (0, _platformFeatureFlags.fg)('platform_editor_elements_drag_and_drop_ed_23189') ? '0.31' : '0.4';
89
+ contentPreviewOneElement.appendChild(clonedDom);
90
+ return contentPreviewOneElement;
91
+ };
92
+ var isGenericPreview = function isGenericPreview(dom, nodeType) {
93
+ var embedCard = dom.querySelector('.embedCardView-content-wrap');
94
+ return (0, _platformFeatureFlags.fg)('platform_editor_elements_drag_and_drop_ed_23189') ? nodeType === 'embedCard' || !!embedCard || nodeType === 'extension' && !!dom.querySelector('iframe') : nodeType === 'embedCard' || !!embedCard || nodeType === 'extension';
95
+ };
96
+ var createPreviewForElement = function createPreviewForElement(dom, nodeType, nodeSpacing) {
97
+ var shouldBeGenericPreview = isGenericPreview(dom, nodeType);
45
98
  if (shouldBeGenericPreview) {
46
- parent.style.border = "".concat(previewStyle.borderWidth, " ").concat(previewStyle.borderStyle, " ").concat(previewStyle.borderColor);
47
- parent.style.borderRadius = previewStyle.borderRadius;
48
- parent.style.backgroundColor = previewStyle.backgroundColor;
49
- parent.style.height = '100%';
50
- parent.setAttribute('data-testid', 'block-ctrl-generic-drag-preview');
99
+ return createGenericPreview();
51
100
  } else {
52
- var resizer = dom.querySelector('.resizer-item');
53
- var clonedDom = resizer && ['mediaSingle', 'table'].includes(nodeType) ?
54
- // Ignored via go/ees005
55
- // eslint-disable-next-line @atlaskit/editor/no-as-casting
56
- resizer.cloneNode(true) :
57
- // Ignored via go/ees005
58
- // eslint-disable-next-line @atlaskit/editor/no-as-casting
59
- dom.cloneNode(true);
60
-
61
- // Remove any margin from the cloned element to ensure is doesn't position incorrectly
62
- clonedDom.style.marginLeft = '0';
63
- clonedDom.style.marginTop = '0';
64
- clonedDom.style.marginRight = '0';
65
- clonedDom.style.marginBottom = '0';
66
- clonedDom.style.boxShadow = 'none';
67
- clonedDom.style.opacity = _browser.browser.windows ? '1' : (0, _platformFeatureFlags.fg)('platform_editor_elements_drag_and_drop_ed_23189') ? '0.31' : '0.4';
68
- parent.appendChild(clonedDom);
101
+ return createContentPreviewElement(dom, nodeType, nodeSpacing);
69
102
  }
70
- container.appendChild(parent);
103
+ };
104
+ var dragPreview = exports.dragPreview = function dragPreview(container, dragPreviewContent) {
105
+ container.style.pointerEvents = 'none';
106
+ if (!Array.isArray(dragPreviewContent) && (0, _typeof2.default)(dragPreviewContent) === 'object') {
107
+ dragPreviewContent = [dragPreviewContent];
108
+ }
109
+ var _getPreviewContainerD2 = getPreviewContainerDimensions(dragPreviewContent),
110
+ maxWidth = _getPreviewContainerD2.width,
111
+ maxHeight = _getPreviewContainerD2.height;
112
+ container.style.width = "".concat(maxWidth, "px");
113
+ container.style.height = "".concat(maxHeight, "px");
114
+ var previewWrapperFragment = document.createDocumentFragment();
115
+ for (var index = 0; index < dragPreviewContent.length; index++) {
116
+ var element = dragPreviewContent[index];
117
+ var contentPreviewOneElement = createPreviewForElement(element.dom, element.nodeType, element.nodeSpacing);
118
+ previewWrapperFragment.appendChild(contentPreviewOneElement);
119
+ }
120
+ container.appendChild(previewWrapperFragment);
71
121
  var scrollParent = document.querySelector('.fabric-editor-popup-scroll-parent');
72
122
  var scrollParentClassNames = scrollParent === null || scrollParent === void 0 ? void 0 : scrollParent.className;
73
-
74
123
  // Add the scroll parent class to the container to ensure the cloned element is styled correctly
75
124
  container.className = scrollParentClassNames || '';
76
125
  container.classList.remove('fabric-editor-popup-scroll-parent');
@@ -1,9 +1,11 @@
1
1
  import React from 'react';
2
2
  import { expandSelectionBounds } from '@atlaskit/editor-common/selection';
3
3
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
4
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
4
5
  import { moveNode } from './editor-commands/move-node';
5
6
  import { moveToLayout } from './editor-commands/move-to-layout';
6
7
  import { createPlugin, key } from './pm-plugins/main';
8
+ import BlockMenu from './ui/block-menu';
7
9
  import { DragHandleMenu } from './ui/drag-handle-menu';
8
10
  import { GlobalStylesWrapper } from './ui/global-styles';
9
11
  export const blockControlsPlugin = ({
@@ -33,7 +35,25 @@ export const blockControlsPlugin = ({
33
35
  anchorName,
34
36
  nodeType,
35
37
  handleOptions
36
- }
38
+ },
39
+ closeMenu: editorExperiment('platform_editor_controls', 'variant1') ? true : undefined
40
+ });
41
+ return tr;
42
+ },
43
+ toggleBlockMenu: options => ({
44
+ tr
45
+ }) => {
46
+ const currMeta = tr.getMeta(key);
47
+ if (options !== null && options !== void 0 && options.closeMenu) {
48
+ tr.setMeta(key, {
49
+ ...currMeta,
50
+ closeMenu: true
51
+ });
52
+ return tr;
53
+ }
54
+ tr.setMeta(key, {
55
+ ...currMeta,
56
+ toggleMenu: true
37
57
  });
38
58
  return tr;
39
59
  },
@@ -108,8 +128,19 @@ export const blockControlsPlugin = ({
108
128
  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
109
129
  };
110
130
  },
111
- contentComponent() {
112
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(DragHandleMenu, {
131
+ contentComponent({
132
+ editorView,
133
+ popupsMountPoint,
134
+ popupsBoundariesElement,
135
+ popupsScrollableElement
136
+ }) {
137
+ return /*#__PURE__*/React.createElement(React.Fragment, null, editorExperiment('platform_editor_controls', 'variant1') ? /*#__PURE__*/React.createElement(BlockMenu, {
138
+ editorView: editorView,
139
+ mountPoint: popupsMountPoint,
140
+ boundariesElement: popupsBoundariesElement,
141
+ scrollableElement: popupsScrollableElement,
142
+ api: api
143
+ }) : /*#__PURE__*/React.createElement(DragHandleMenu, {
113
144
  api: api
114
145
  }), /*#__PURE__*/React.createElement(GlobalStylesWrapper, null));
115
146
  }
@@ -1,5 +1,6 @@
1
1
  import { createElement } from 'react';
2
2
  import uuid from 'uuid';
3
+ import { expandSelectionBounds } from '@atlaskit/editor-common/selection';
3
4
  import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
4
5
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
5
6
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
@@ -153,6 +154,16 @@ export const dropTargetDecorations = (newState, api, formatMessage, nodeViewPort
153
154
  prevNodeStack.push(node);
154
155
  };
155
156
  const isAdvancedLayoutsPreRelease2 = editorExperiment('advanced_layouts', true);
157
+
158
+ // For deciding to show drop targets or not when multiple nodes are selected
159
+ const selection = newState.selection;
160
+ const {
161
+ $anchor: expandedAnchor,
162
+ $head: expandedHead
163
+ } = expandSelectionBounds(selection.$anchor, selection.$head);
164
+ const selectionFrom = Math.min(expandedAnchor.pos, expandedHead.pos);
165
+ const selectionTo = Math.max(expandedAnchor.pos, expandedHead.pos);
166
+ const handleInsideSelection = activeNodePos !== undefined && activeNodePos >= selectionFrom && activeNodePos <= selectionTo;
156
167
  newState.doc.nodesBetween(docFrom, docTo, (node, pos, parent, index) => {
157
168
  let depth = 0;
158
169
  // drop target deco at the end position
@@ -187,10 +198,6 @@ export const dropTargetDecorations = (newState, api, formatMessage, nodeViewPort
187
198
 
188
199
  // When multi select is on, validate all the nodes in the selection instead of just the handle node
189
200
  if (isMultiSelect) {
190
- const selection = newState.selection;
191
- const selectionFrom = selection.$from.pos;
192
- const selectionTo = selection.$to.pos;
193
- const handleInsideSelection = activeNodePos !== undefined && activeNodePos >= selectionFrom - 1 && activeNodePos <= selectionTo;
194
201
  const selectionSlice = newState.doc.slice(selectionFrom, selectionTo, false);
195
202
  const selectionSliceChildCount = selectionSlice.content.childCount;
196
203
  let canDropSingleNode = true;
@@ -198,7 +205,7 @@ export const dropTargetDecorations = (newState, api, formatMessage, nodeViewPort
198
205
 
199
206
  // when there is only one node in the slice, use the same logic as when multi select is not on
200
207
  if (selectionSliceChildCount > 1 && handleInsideSelection) {
201
- canDropMultipleNodes = canMoveSliceToIndex(selectionSlice, selectionFrom, newState.doc, parent, index, $pos);
208
+ canDropMultipleNodes = canMoveSliceToIndex(selectionSlice, selectionFrom, parent, index, $pos);
202
209
  } else {
203
210
  canDropSingleNode = !!(activePMNode && canMoveNodeToIndex(parent, index, activePMNode, $pos, node));
204
211
  }
@@ -281,11 +281,12 @@ export const newApply = (api, formatMessage, tr, currentState, newState, flags,
281
281
  }
282
282
  }
283
283
  const newActiveNode = isEmptyDoc || !(meta !== null && meta !== void 0 && meta.activeNode) && findHandleDec(decorations, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.pos, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.pos).length === 0 ? null : latestActiveNode;
284
+ const isMenuOpenNew = editorExperiment('platform_editor_controls', 'variant1') ? meta !== null && meta !== void 0 && meta.closeMenu ? false : meta !== null && meta !== void 0 && meta.toggleMenu ? !isMenuOpen : isMenuOpen : meta !== null && meta !== void 0 && meta.toggleMenu ? !isMenuOpen : isMenuOpen;
284
285
  return {
285
286
  decorations,
286
287
  activeNode: newActiveNode,
287
288
  isDragging: (_meta$isDragging2 = meta === null || meta === void 0 ? void 0 : meta.isDragging) !== null && _meta$isDragging2 !== void 0 ? _meta$isDragging2 : isDragging,
288
- isMenuOpen: meta !== null && meta !== void 0 && meta.toggleMenu ? !isMenuOpen : isMenuOpen,
289
+ isMenuOpen: isMenuOpenNew,
289
290
  editorHeight: (_meta$editorHeight = meta === null || meta === void 0 ? void 0 : meta.editorHeight) !== null && _meta$editorHeight !== void 0 ? _meta$editorHeight : editorHeight,
290
291
  editorWidthLeft: (_meta$editorWidthLeft = meta === null || meta === void 0 ? void 0 : meta.editorWidthLeft) !== null && _meta$editorWidthLeft !== void 0 ? _meta$editorWidthLeft : editorWidthLeft,
291
292
  editorWidthRight: (_meta$editorWidthRigh = meta === null || meta === void 0 ? void 0 : meta.editorWidthRight) !== null && _meta$editorWidthRigh !== void 0 ? _meta$editorWidthRigh : editorWidthRight,
@@ -96,7 +96,7 @@ export const setCursorPositionAtMovedNode = (tr, start) => {
96
96
  * @param handlePos
97
97
  * @returns
98
98
  */
99
- export const isHandleInSelection = (state, selection, handlePos) => {
99
+ export const isHandleCorrelatedToSelection = (state, selection, handlePos) => {
100
100
  if (selection.empty) {
101
101
  return false;
102
102
  }
@@ -114,8 +114,9 @@ export function canMoveNodeToIndex(destParent, indexIntoParent, srcNode, $destNo
114
114
  }
115
115
  return destParent.canReplaceWith(indexIntoParent, indexIntoParent, srcNodeType);
116
116
  }
117
- export function canMoveSliceToIndex(slice, sliceFromPos, doc, destParent, indexIntoParent, $destNodePos, destNode) {
117
+ export function canMoveSliceToIndex(slice, sliceFromPos, destParent, indexIntoParent, $destNodePos, destNode) {
118
118
  let canMoveNodes = true;
119
+ const doc = $destNodePos.doc;
119
120
  const nodesPos = [];
120
121
  for (let i = 0; i < slice.content.childCount; i++) {
121
122
  const node = slice.content.maybeChild(i);
@@ -0,0 +1,92 @@
1
+ /* eslint-disable @atlaskit/design-system/prefer-primitives */
2
+ /**
3
+ * @jsxRuntime classic
4
+ * @jsx jsx
5
+ */
6
+
7
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
8
+ import { jsx } from '@emotion/react';
9
+ import { copy, deleteKey, dragToMoveDown, dragToMoveUp, tooltip } from '@atlaskit/editor-common/keymaps';
10
+ import commonMessages, { blockControlsMessages } from '@atlaskit/editor-common/messages';
11
+ import { shortcutStyle } from '@atlaskit/editor-shared-styles/shortcut';
12
+ import ArrowDownIcon from '@atlaskit/icon/core/arrow-down';
13
+ import ArrowUpIcon from '@atlaskit/icon/core/arrow-up';
14
+ import CopyIcon from '@atlaskit/icon/core/copy';
15
+ import DeleteIcon from '@atlaskit/icon/core/delete';
16
+ import { moveNodeViaShortcut } from '../editor-commands/move-node';
17
+ import { DIRECTION } from '../pm-plugins/utils/consts';
18
+ export const getBlockMenuItems = formatMessage => {
19
+ return [{
20
+ items: [{
21
+ content: formatMessage(blockControlsMessages.moveUp),
22
+ elemBefore: jsx(ArrowUpIcon, {
23
+ label: ""
24
+ }),
25
+ value: {
26
+ name: 'moveUp'
27
+ },
28
+ key: 'move_up',
29
+ // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage, @atlaskit/ui-styling-standard/no-imported-style-values
30
+ elemAfter: jsx("div", {
31
+ css: shortcutStyle
32
+ }, tooltip(dragToMoveUp))
33
+ }, {
34
+ content: formatMessage(blockControlsMessages.moveDown),
35
+ elemBefore: jsx(ArrowDownIcon, {
36
+ label: ""
37
+ }),
38
+ value: {
39
+ name: 'moveDown'
40
+ },
41
+ key: 'move_down',
42
+ // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage, @atlaskit/ui-styling-standard/no-imported-style-values
43
+ elemAfter: jsx("div", {
44
+ css: shortcutStyle
45
+ }, tooltip(dragToMoveDown))
46
+ }]
47
+ }, {
48
+ items: [{
49
+ content: formatMessage(commonMessages.copyToClipboard),
50
+ value: {
51
+ name: 'copy'
52
+ },
53
+ elemBefore: jsx(CopyIcon, {
54
+ label: ""
55
+ }),
56
+ key: 'copy',
57
+ // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage, @atlaskit/ui-styling-standard/no-imported-style-values
58
+ elemAfter: jsx("div", {
59
+ css: shortcutStyle
60
+ }, tooltip(copy))
61
+ }, {
62
+ content: formatMessage(blockControlsMessages.delete),
63
+ value: {
64
+ name: 'delete'
65
+ },
66
+ elemBefore: jsx(DeleteIcon, {
67
+ label: ""
68
+ }),
69
+ key: 'delete',
70
+ // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage, @atlaskit/ui-styling-standard/no-imported-style-values
71
+ elemAfter: jsx("div", {
72
+ css: shortcutStyle
73
+ }, tooltip(deleteKey))
74
+ }]
75
+ }];
76
+ };
77
+ export const menuItemsCallback = {
78
+ moveUp: (api, formatMessage) => {
79
+ return moveNodeViaShortcut(api, DIRECTION.UP, formatMessage);
80
+ },
81
+ moveDown: (api, formatMessage) => {
82
+ return moveNodeViaShortcut(api, DIRECTION.DOWN, formatMessage);
83
+ },
84
+ copy: () => {
85
+ // TODO: implement copy
86
+ // console.log('copy');
87
+ },
88
+ delete: () => {
89
+ // TODO: implement delete
90
+ // console.log('delete');
91
+ }
92
+ };