@atlaskit/editor-plugin-block-controls 2.13.10 → 2.13.12

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 (33) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cjs/commands/move-to-layout.js +58 -34
  3. package/dist/cjs/consts.js +3 -2
  4. package/dist/cjs/pm-plugins/decorations-drop-target.js +13 -8
  5. package/dist/cjs/ui/drop-target-v2.js +3 -2
  6. package/dist/cjs/ui/inline-drop-target.js +1 -1
  7. package/dist/cjs/utils/inline-drop-target.js +2 -1
  8. package/dist/cjs/utils/validation.js +15 -2
  9. package/dist/es2019/commands/move-to-layout.js +50 -25
  10. package/dist/es2019/consts.js +2 -1
  11. package/dist/es2019/pm-plugins/decorations-drop-target.js +14 -9
  12. package/dist/es2019/ui/drop-target-v2.js +3 -2
  13. package/dist/es2019/ui/inline-drop-target.js +1 -1
  14. package/dist/es2019/utils/inline-drop-target.js +7 -3
  15. package/dist/es2019/utils/validation.js +14 -1
  16. package/dist/esm/commands/move-to-layout.js +59 -35
  17. package/dist/esm/consts.js +2 -1
  18. package/dist/esm/pm-plugins/decorations-drop-target.js +14 -9
  19. package/dist/esm/ui/drop-target-v2.js +3 -2
  20. package/dist/esm/ui/inline-drop-target.js +1 -1
  21. package/dist/esm/utils/inline-drop-target.js +3 -2
  22. package/dist/esm/utils/validation.js +14 -1
  23. package/dist/types/consts.d.ts +1 -0
  24. package/dist/types/pm-plugins/decorations-drop-target.d.ts +1 -1
  25. package/dist/types/ui/drop-target-v2.d.ts +1 -0
  26. package/dist/types/utils/inline-drop-target.d.ts +1 -1
  27. package/dist/types/utils/validation.d.ts +3 -2
  28. package/dist/types-ts4.5/consts.d.ts +1 -0
  29. package/dist/types-ts4.5/pm-plugins/decorations-drop-target.d.ts +1 -1
  30. package/dist/types-ts4.5/ui/drop-target-v2.d.ts +1 -0
  31. package/dist/types-ts4.5/utils/inline-drop-target.d.ts +1 -1
  32. package/dist/types-ts4.5/utils/validation.d.ts +3 -2
  33. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 2.13.12
4
+
5
+ ### Patch Changes
6
+
7
+ - [#163103](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/163103)
8
+ [`ec14916563763`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/ec14916563763) -
9
+ [ux] [ED-25060] Implement drag and drop a layout column to another layout section
10
+
11
+ ## 2.13.11
12
+
13
+ ### Patch Changes
14
+
15
+ - [`dda502e353b44`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/dda502e353b44) -
16
+ [ux] [ED-25317] Implement drag and drop a layout column within the same layout section
17
+
3
18
  ## 2.13.10
4
19
 
5
20
  ### Patch Changes
@@ -8,6 +8,7 @@ var _model = require("@atlaskit/editor-prosemirror/model");
8
8
  var _state = require("@atlaskit/editor-prosemirror/state");
9
9
  var _consts = require("../consts");
10
10
  var _consts2 = require("../ui/consts");
11
+ var _validation = require("../utils/validation");
11
12
  var createNewLayout = function createNewLayout(schema, layoutContents) {
12
13
  if (layoutContents.length === 0 || layoutContents.length > (0, _consts.maxLayoutColumnSupported)()) {
13
14
  return null;
@@ -32,37 +33,60 @@ var createNewLayout = function createNewLayout(schema, layoutContents) {
32
33
  }
33
34
  return null;
34
35
  };
35
- var updateColumnWidths = function updateColumnWidths(tr, layoutNode, layoutNodePos, newColumnWidth) {
36
+ var updateColumnWidths = function updateColumnWidths(tr, layoutNode, layoutNodePos, childCount) {
37
+ var newColumnWidth = _consts2.DEFAULT_COLUMN_DISTRIBUTIONS[childCount];
36
38
  if (newColumnWidth) {
37
39
  layoutNode.content.forEach(function (node, offset) {
38
40
  if (node.type.name === 'layoutColumn') {
39
- tr = tr.setNodeAttribute(layoutNodePos + offset + 1, 'width', newColumnWidth);
41
+ tr.setNodeAttribute(layoutNodePos + offset + 1, 'width', newColumnWidth);
40
42
  }
41
43
  });
42
44
  }
43
- return tr;
45
+ return {
46
+ newColumnWidth: newColumnWidth,
47
+ tr: tr
48
+ };
44
49
  };
45
-
46
- /**
47
- * Insert a node into an existing layout at position `to` and delete the node
48
- */
49
- var moveNode = function moveNode(from, to, newNode, sourceNodeSize, tr) {
50
- tr.insert(to, newNode).setSelection(new _state.NodeSelection(tr.doc.resolve(to))).scrollIntoView();
51
- var mappedFrom = tr.mapping.map(from);
52
- var mappedFromEnd = mappedFrom + sourceNodeSize;
53
- tr.delete(mappedFrom, mappedFromEnd);
50
+ var moveToExistingLayout = function moveToExistingLayout(toLayout, toLayoutPos, sourceNode, from, to, tr, isSameLayout) {
51
+ if (isSameLayout) {
52
+ // reorder columns
53
+ tr.delete(from, from + sourceNode.nodeSize);
54
+ var mappedTo = tr.mapping.map(to);
55
+ tr.insert(mappedTo, sourceNode).setSelection(new _state.NodeSelection(tr.doc.resolve(mappedTo))).scrollIntoView();
56
+ } else if (toLayout.childCount < (0, _consts.maxLayoutColumnSupported)()) {
57
+ insertToDestination(tr, to, sourceNode, toLayout, toLayoutPos);
58
+ var mappedFrom = tr.mapping.map(from);
59
+ removeFromSource(tr, tr.doc.resolve(mappedFrom));
60
+ }
54
61
  return tr;
55
62
  };
56
- var moveToExistingLayout = function moveToExistingLayout(toLayout, toLayoutPos, sourceNode, from, to, tr) {
57
- if (toLayout.childCount < (0, _consts.maxLayoutColumnSupported)()) {
58
- var newColumnWidth = _consts2.DEFAULT_COLUMN_DISTRIBUTIONS[toLayout.childCount + 1];
59
- updateColumnWidths(tr, toLayout, toLayoutPos, newColumnWidth);
60
- var _ref2 = tr.doc.type.schema.nodes || {},
61
- layoutColumn = _ref2.layoutColumn;
62
- moveNode(from, to, layoutColumn.create({
63
- width: newColumnWidth
64
- }, sourceNode), sourceNode.nodeSize, tr);
63
+ var removeFromSource = function removeFromSource(tr, $from) {
64
+ var sourceNode = $from.nodeAfter;
65
+ var sourceParent = $from.parent;
66
+ if (!sourceNode) {
67
+ return tr;
68
+ }
69
+ var sourceNodeEndPos = $from.pos + sourceNode.nodeSize;
70
+ if (sourceNode.type.name === 'layoutColumn') {
71
+ if (sourceParent.childCount === _consts.MIN_LAYOUT_COLUMN) {
72
+ tr.delete($from.pos + 1, sourceNodeEndPos - 1);
73
+ return tr;
74
+ } else {
75
+ updateColumnWidths(tr, $from.parent, $from.before($from.depth), sourceParent.childCount - 1);
76
+ }
65
77
  }
78
+ tr.delete($from.pos, sourceNodeEndPos);
79
+ return tr;
80
+ };
81
+ var insertToDestination = function insertToDestination(tr, to, sourceNode, toLayout, toLayoutPos) {
82
+ var _ref2 = updateColumnWidths(tr, toLayout, toLayoutPos, toLayout.childCount + 1) || {},
83
+ newColumnWidth = _ref2.newColumnWidth;
84
+ var _ref3 = tr.doc.type.schema.nodes || {},
85
+ layoutColumn = _ref3.layoutColumn;
86
+ var content = layoutColumn.createChecked({
87
+ width: newColumnWidth
88
+ }, sourceNode.type.name === 'layoutColumn' ? sourceNode.content : sourceNode);
89
+ tr.insert(to, content).setSelection(new _state.NodeSelection(tr.doc.resolve(to))).scrollIntoView();
66
90
  return tr;
67
91
  };
68
92
 
@@ -74,10 +98,10 @@ var canMoveToLayout = function canMoveToLayout(from, to, tr) {
74
98
  if (from === to) {
75
99
  return;
76
100
  }
77
- var _ref3 = tr.doc.type.schema.nodes || {},
78
- layoutSection = _ref3.layoutSection,
79
- layoutColumn = _ref3.layoutColumn,
80
- doc = _ref3.doc;
101
+ var _ref4 = tr.doc.type.schema.nodes || {},
102
+ layoutSection = _ref4.layoutSection,
103
+ layoutColumn = _ref4.layoutColumn,
104
+ doc = _ref4.doc;
81
105
 
82
106
  // layout plugin does not exist
83
107
  if (!layoutSection || !layoutColumn) {
@@ -106,8 +130,8 @@ var canMoveToLayout = function canMoveToLayout(from, to, tr) {
106
130
  };
107
131
  var moveToLayout = exports.moveToLayout = function moveToLayout(api) {
108
132
  return function (from, to, options) {
109
- return function (_ref4) {
110
- var tr = _ref4.tr;
133
+ return function (_ref5) {
134
+ var tr = _ref5.tr;
111
135
  var canMove = canMoveToLayout(from, to, tr);
112
136
  if (!canMove) {
113
137
  return tr;
@@ -116,11 +140,11 @@ var moveToLayout = exports.moveToLayout = function moveToLayout(api) {
116
140
  fromNode = canMove.fromNode,
117
141
  $from = canMove.$from,
118
142
  $to = canMove.$to;
119
- var _ref5 = tr.doc.type.schema.nodes || {},
120
- layoutSection = _ref5.layoutSection,
121
- layoutColumn = _ref5.layoutColumn;
122
- var _ref6 = tr.doc.type.schema.marks || {},
123
- breakout = _ref6.breakout;
143
+ var _ref6 = tr.doc.type.schema.nodes || {},
144
+ layoutSection = _ref6.layoutSection,
145
+ layoutColumn = _ref6.layoutColumn;
146
+ var _ref7 = tr.doc.type.schema.marks || {},
147
+ breakout = _ref7.breakout;
124
148
  var fromNodeWithoutBreakout = fromNode;
125
149
 
126
150
  // remove breakout from node;
@@ -136,12 +160,12 @@ var moveToLayout = exports.moveToLayout = function moveToLayout(api) {
136
160
  }
137
161
  if (toNode.type === layoutSection) {
138
162
  var toPos = options !== null && options !== void 0 && options.moveToEnd ? to + toNode.nodeSize - 1 : to + 1;
139
- return moveToExistingLayout(toNode, to, fromNodeWithoutBreakout, from, toPos, tr);
163
+ return moveToExistingLayout(toNode, to, fromNodeWithoutBreakout, from, toPos, tr, (0, _validation.isInSameLayout)($from, $to));
140
164
  } else if (toNode.type === layoutColumn) {
141
165
  var toLayout = $to.parent;
142
166
  var toLayoutPos = to - $to.parentOffset - 1;
143
167
  var _toPos = options !== null && options !== void 0 && options.moveToEnd ? to + toNode.nodeSize : to;
144
- return moveToExistingLayout(toLayout, toLayoutPos, fromNodeWithoutBreakout, from, _toPos, tr);
168
+ return moveToExistingLayout(toLayout, toLayoutPos, fromNodeWithoutBreakout, from, _toPos, tr, (0, _validation.isInSameLayout)($from, $to));
145
169
  } else {
146
170
  var toNodeWithoutBreakout = toNode;
147
171
 
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.maxLayoutColumnSupported = exports.DIRECTION = void 0;
6
+ exports.maxLayoutColumnSupported = exports.MIN_LAYOUT_COLUMN = exports.DIRECTION = void 0;
7
7
  var _advancedLayoutsFlags = require("./utils/advanced-layouts-flags");
8
8
  var DIRECTION = exports.DIRECTION = /*#__PURE__*/function (DIRECTION) {
9
9
  DIRECTION["UP"] = "up";
@@ -14,4 +14,5 @@ var DIRECTION = exports.DIRECTION = /*#__PURE__*/function (DIRECTION) {
14
14
  }({});
15
15
  var maxLayoutColumnSupported = exports.maxLayoutColumnSupported = function maxLayoutColumnSupported() {
16
16
  return (0, _advancedLayoutsFlags.isPreRelease2)() ? 5 : 3;
17
- };
17
+ };
18
+ var MIN_LAYOUT_COLUMN = exports.MIN_LAYOUT_COLUMN = 2;
@@ -88,7 +88,7 @@ var findDropTargetDecs = exports.findDropTargetDecs = function findDropTargetDec
88
88
  return spec.type === _decorationsCommon.TYPE_DROP_TARGET_DEC;
89
89
  });
90
90
  };
91
- var createDropTargetDecoration = exports.createDropTargetDecoration = function createDropTargetDecoration(pos, props, side, anchorRectCache) {
91
+ var createDropTargetDecoration = exports.createDropTargetDecoration = function createDropTargetDecoration(pos, props, side, anchorRectCache, isSameLayout) {
92
92
  return _view.Decoration.widget(pos, function (_, getPos) {
93
93
  var element = document.createElement('div');
94
94
  element.setAttribute('data-blocks-drop-target-container', 'true');
@@ -102,7 +102,8 @@ var createDropTargetDecoration = exports.createDropTargetDecoration = function c
102
102
  element.style.setProperty('display', 'block');
103
103
  _reactDom.default.render( /*#__PURE__*/(0, _react.createElement)(_dropTargetV.DropTargetV2, _objectSpread(_objectSpread({}, props), {}, {
104
104
  getPos: getPos,
105
- anchorRectCache: anchorRectCache
105
+ anchorRectCache: anchorRectCache,
106
+ isSameLayout: isSameLayout
106
107
  })), element);
107
108
  } else {
108
109
  _reactDom.default.render( /*#__PURE__*/(0, _react.createElement)(_dropTarget.DropTarget, _objectSpread(_objectSpread({}, props), {}, {
@@ -136,7 +137,8 @@ var dropTargetDecorations = exports.dropTargetDecorations = function dropTargetD
136
137
  var docTo = to === undefined || to > POS_END_OF_DOC ? POS_END_OF_DOC : to;
137
138
  var prevNode;
138
139
  var activeNodePos = activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos;
139
- var activePMNode = typeof activeNodePos === 'number' && newState.doc.resolve(activeNodePos).nodeAfter;
140
+ var $activeNodePos = typeof activeNodePos === 'number' && newState.doc.resolve(activeNodePos);
141
+ var activePMNode = $activeNodePos && $activeNodePos.nodeAfter;
140
142
  anchorRectCache === null || anchorRectCache === void 0 || anchorRectCache.clear();
141
143
  var prevNodeStack = [];
142
144
  var popNodeStack = function popNodeStack(depth) {
@@ -156,12 +158,15 @@ var dropTargetDecorations = exports.dropTargetDecorations = function dropTargetD
156
158
  var depth = 0;
157
159
  // drop target deco at the end position
158
160
  var endPos;
161
+ var $pos = newState.doc.resolve(pos);
162
+ var isSameLayout = $activeNodePos && (0, _validation.isInSameLayout)($activeNodePos, $pos);
159
163
  if ((0, _experiments.editorExperiment)('nested-dnd', true)) {
160
- depth = newState.doc.resolve(pos).depth;
164
+ depth = $pos.depth;
161
165
  if (isAdvancedLayoutsPreRelease2) {
162
- if (node.type.name === 'layoutColumn' && (parent === null || parent === void 0 ? void 0 : parent.type.name) === 'layoutSection' && (parent === null || parent === void 0 ? void 0 : parent.firstChild) !== node &&
166
+ if (node.type.name === 'layoutColumn' && (parent === null || parent === void 0 ? void 0 : parent.type.name) === 'layoutSection' && (parent === null || parent === void 0 ? void 0 : parent.firstChild) !== node && (
163
167
  // Not the first node
164
- (parent === null || parent === void 0 ? void 0 : parent.childCount) < (0, _consts.maxLayoutColumnSupported)()) {
168
+ (parent === null || parent === void 0 ? void 0 : parent.childCount) < (0, _consts.maxLayoutColumnSupported)() || isSameLayout)) {
169
+ // Add drop target for layout columns
165
170
  decs.push(createLayoutDropTargetDecoration(pos, {
166
171
  api: api,
167
172
  parent: parent,
@@ -185,7 +190,7 @@ var dropTargetDecorations = exports.dropTargetDecorations = function dropTargetD
185
190
  }
186
191
  return shouldDescend(node); //skip over, don't consider it a valid depth
187
192
  }
188
- var canDrop = activePMNode && (0, _validation.canMoveNodeToIndex)(parent, index, activePMNode);
193
+ var canDrop = activePMNode && (0, _validation.canMoveNodeToIndex)(parent, index, activePMNode, node);
189
194
 
190
195
  //NOTE: This will block drop targets showing for nodes that are valid after transformation (i.e. expand -> nestedExpand)
191
196
  if (!canDrop && !(0, _dragTargetDebug.isBlocksDragTargetDebug)()) {
@@ -212,7 +217,7 @@ var dropTargetDecorations = exports.dropTargetDecorations = function dropTargetD
212
217
  parentNode: parent || undefined,
213
218
  formatMessage: formatMessage,
214
219
  dropTargetStyle: shouldShowFullHeight ? 'remainingHeight' : 'default'
215
- }, -1, anchorRectCache));
220
+ }, -1, anchorRectCache, isSameLayout));
216
221
  if (endPos !== undefined) {
217
222
  decs.push(createDropTargetDecoration(endPos, {
218
223
  api: api,
@@ -187,7 +187,8 @@ var DropTargetV2 = exports.DropTargetV2 = function DropTargetV2(props) {
187
187
  formatMessage = props.formatMessage,
188
188
  anchorRectCache = props.anchorRectCache,
189
189
  _props$dropTargetStyl = props.dropTargetStyle,
190
- dropTargetStyle = _props$dropTargetStyl === void 0 ? 'default' : _props$dropTargetStyl;
190
+ dropTargetStyle = _props$dropTargetStyl === void 0 ? 'default' : _props$dropTargetStyl,
191
+ isSameLayout = props.isSameLayout;
191
192
  var _useState = (0, _react.useState)(false),
192
193
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
193
194
  isDraggedOver = _useState2[0],
@@ -254,7 +255,7 @@ var DropTargetV2 = exports.DropTargetV2 = function DropTargetV2(props) {
254
255
  anchorRectCache: anchorRectCache,
255
256
  position: "lower",
256
257
  isNestedDropTarget: isNestedDropTarget
257
- }), (0, _inlineDropTarget.shouldAllowInlineDropTarget)(isNestedDropTarget, nextNode) && (0, _react2.jsx)(_react.Fragment, null, (0, _react2.jsx)(_inlineDropTarget2.InlineDropTarget, (0, _extends2.default)({}, props, {
258
+ }), (0, _inlineDropTarget.shouldAllowInlineDropTarget)(isNestedDropTarget, nextNode, isSameLayout) && (0, _react2.jsx)(_react.Fragment, null, (0, _react2.jsx)(_inlineDropTarget2.InlineDropTarget, (0, _extends2.default)({}, props, {
258
259
  position: "left"
259
260
  })), (0, _react2.jsx)(_inlineDropTarget2.InlineDropTarget, (0, _extends2.default)({}, props, {
260
261
  position: "right"
@@ -172,7 +172,7 @@ var InlineDropTarget = exports.InlineDropTarget = function InlineDropTarget(_ref
172
172
  }, [onDrop, setIsDraggedOver]);
173
173
  return (0, _react2.jsx)("div", {
174
174
  ref: ref,
175
- "data-test-id": "drop-target-hover-zone-".concat(position),
175
+ "data-testid": "drop-target-hover-zone-".concat(position),
176
176
  css: [hoverZoneCommonStyle, inlineHoverZoneRectStyle]
177
177
  }, isDraggedOver || (0, _dragTargetDebug.isBlocksDragTargetDebug)() ? (0, _react2.jsx)(_box.DropIndicator, {
178
178
  edge: dropIndicatorPos
@@ -9,6 +9,7 @@ var _consts = require("../consts");
9
9
  var _advancedLayoutsFlags = require("./advanced-layouts-flags");
10
10
  var _checkMediaLayout = require("./check-media-layout");
11
11
  var shouldAllowInlineDropTarget = exports.shouldAllowInlineDropTarget = function shouldAllowInlineDropTarget(isNested, node) {
12
+ var isSameLayout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
12
13
  if (!(0, _advancedLayoutsFlags.isPreRelease1)() || isNested) {
13
14
  return false;
14
15
  }
@@ -16,7 +17,7 @@ var shouldAllowInlineDropTarget = exports.shouldAllowInlineDropTarget = function
16
17
  return false;
17
18
  }
18
19
  if ((node === null || node === void 0 ? void 0 : node.type.name) === 'layoutSection') {
19
- return node.childCount < (0, _consts.maxLayoutColumnSupported)();
20
+ return node.childCount < (0, _consts.maxLayoutColumnSupported)() || (0, _advancedLayoutsFlags.isPreRelease2)() && isSameLayout;
20
21
  }
21
22
  return !(0, _utils.isEmptyParagraph)(node);
22
23
  };
@@ -5,10 +5,11 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.canMoveNodeToIndex = canMoveNodeToIndex;
8
- exports.transformSliceExpandToNestedExpand = exports.transformExpandToNestedExpand = exports.memoizedTransformExpandToNestedExpand = exports.isNestedExpand = exports.isLayoutColumn = exports.isInsideTable = exports.isExpand = exports.isDoc = void 0;
8
+ exports.transformSliceExpandToNestedExpand = exports.transformExpandToNestedExpand = exports.memoizedTransformExpandToNestedExpand = exports.isNestedExpand = exports.isLayoutColumn = exports.isInsideTable = exports.isInSameLayout = exports.isExpand = exports.isDoc = void 0;
9
9
  var _memoizeOne = _interopRequireDefault(require("memoize-one"));
10
10
  var _model = require("@atlaskit/editor-prosemirror/model");
11
11
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
12
+ var _advancedLayoutsFlags = require("../utils/advanced-layouts-flags");
12
13
  var isInsideTable = exports.isInsideTable = function isInsideTable(nodeType) {
13
14
  var _nodeType$schema$node = nodeType.schema.nodes,
14
15
  tableCell = _nodeType$schema$node.tableCell,
@@ -27,6 +28,13 @@ var isExpand = exports.isExpand = function isExpand(nodeType) {
27
28
  var isNestedExpand = exports.isNestedExpand = function isNestedExpand(nodeType) {
28
29
  return nodeType === nodeType.schema.nodes.nestedExpand;
29
30
  };
31
+ var isInSameLayout = exports.isInSameLayout = function isInSameLayout($from, $to) {
32
+ var fromNode = $from.nodeAfter;
33
+ var toNode = $to.nodeAfter;
34
+ return !!(fromNode && toNode && fromNode.type.name === 'layoutColumn' && ['layoutSection', 'layoutColumn'].includes(toNode.type.name) && (
35
+ // fromNode can either be in the same layoutSection as toNode or is a layoutColumn inside the toNode (type layoutSection)
36
+ $from.sameParent($to) || $from.parent === toNode));
37
+ };
30
38
 
31
39
  /**
32
40
  * This function converts an expand into a nested expand,
@@ -69,7 +77,12 @@ var memoizedTransformExpandToNestedExpand = exports.memoizedTransformExpandToNes
69
77
  return null;
70
78
  }
71
79
  });
72
- function canMoveNodeToIndex(destParent, indexIntoParent, srcNode) {
80
+ function canMoveNodeToIndex(destParent, indexIntoParent, srcNode, destNode) {
81
+ if ((0, _advancedLayoutsFlags.isPreRelease2)() &&
82
+ // Allow drag layout column and drop into layout section
83
+ srcNode.type.name === 'layoutColumn' && (destNode === null || destNode === void 0 ? void 0 : destNode.type.name) === 'layoutSection') {
84
+ return true;
85
+ }
73
86
  var srcNodeType = srcNode.type;
74
87
  var parentNodeType = destParent === null || destParent === void 0 ? void 0 : destParent.type.name;
75
88
  var activeNodeType = srcNode === null || srcNode === void 0 ? void 0 : srcNode.type.name;
@@ -1,7 +1,8 @@
1
1
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
2
  import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
3
- import { maxLayoutColumnSupported } from '../consts';
3
+ import { maxLayoutColumnSupported, MIN_LAYOUT_COLUMN } from '../consts';
4
4
  import { DEFAULT_COLUMN_DISTRIBUTIONS } from '../ui/consts';
5
+ import { isInSameLayout } from '../utils/validation';
5
6
  const createNewLayout = (schema, layoutContents) => {
6
7
  if (layoutContents.length === 0 || layoutContents.length > maxLayoutColumnSupported()) {
7
8
  return null;
@@ -27,38 +28,62 @@ const createNewLayout = (schema, layoutContents) => {
27
28
  }
28
29
  return null;
29
30
  };
30
- const updateColumnWidths = (tr, layoutNode, layoutNodePos, newColumnWidth) => {
31
+ const updateColumnWidths = (tr, layoutNode, layoutNodePos, childCount) => {
32
+ const newColumnWidth = DEFAULT_COLUMN_DISTRIBUTIONS[childCount];
31
33
  if (newColumnWidth) {
32
34
  layoutNode.content.forEach((node, offset) => {
33
35
  if (node.type.name === 'layoutColumn') {
34
- tr = tr.setNodeAttribute(layoutNodePos + offset + 1, 'width', newColumnWidth);
36
+ tr.setNodeAttribute(layoutNodePos + offset + 1, 'width', newColumnWidth);
35
37
  }
36
38
  });
37
39
  }
38
- return tr;
40
+ return {
41
+ newColumnWidth,
42
+ tr
43
+ };
39
44
  };
40
-
41
- /**
42
- * Insert a node into an existing layout at position `to` and delete the node
43
- */
44
- const moveNode = (from, to, newNode, sourceNodeSize, tr) => {
45
- tr.insert(to, newNode).setSelection(new NodeSelection(tr.doc.resolve(to))).scrollIntoView();
46
- const mappedFrom = tr.mapping.map(from);
47
- const mappedFromEnd = mappedFrom + sourceNodeSize;
48
- tr.delete(mappedFrom, mappedFromEnd);
45
+ const moveToExistingLayout = (toLayout, toLayoutPos, sourceNode, from, to, tr, isSameLayout) => {
46
+ if (isSameLayout) {
47
+ // reorder columns
48
+ tr.delete(from, from + sourceNode.nodeSize);
49
+ const mappedTo = tr.mapping.map(to);
50
+ tr.insert(mappedTo, sourceNode).setSelection(new NodeSelection(tr.doc.resolve(mappedTo))).scrollIntoView();
51
+ } else if (toLayout.childCount < maxLayoutColumnSupported()) {
52
+ insertToDestination(tr, to, sourceNode, toLayout, toLayoutPos);
53
+ const mappedFrom = tr.mapping.map(from);
54
+ removeFromSource(tr, tr.doc.resolve(mappedFrom));
55
+ }
49
56
  return tr;
50
57
  };
51
- const moveToExistingLayout = (toLayout, toLayoutPos, sourceNode, from, to, tr) => {
52
- if (toLayout.childCount < maxLayoutColumnSupported()) {
53
- const newColumnWidth = DEFAULT_COLUMN_DISTRIBUTIONS[toLayout.childCount + 1];
54
- updateColumnWidths(tr, toLayout, toLayoutPos, newColumnWidth);
55
- const {
56
- layoutColumn
57
- } = tr.doc.type.schema.nodes || {};
58
- moveNode(from, to, layoutColumn.create({
59
- width: newColumnWidth
60
- }, sourceNode), sourceNode.nodeSize, tr);
58
+ const removeFromSource = (tr, $from) => {
59
+ const sourceNode = $from.nodeAfter;
60
+ const sourceParent = $from.parent;
61
+ if (!sourceNode) {
62
+ return tr;
61
63
  }
64
+ const sourceNodeEndPos = $from.pos + sourceNode.nodeSize;
65
+ if (sourceNode.type.name === 'layoutColumn') {
66
+ if (sourceParent.childCount === MIN_LAYOUT_COLUMN) {
67
+ tr.delete($from.pos + 1, sourceNodeEndPos - 1);
68
+ return tr;
69
+ } else {
70
+ updateColumnWidths(tr, $from.parent, $from.before($from.depth), sourceParent.childCount - 1);
71
+ }
72
+ }
73
+ tr.delete($from.pos, sourceNodeEndPos);
74
+ return tr;
75
+ };
76
+ const insertToDestination = (tr, to, sourceNode, toLayout, toLayoutPos) => {
77
+ const {
78
+ newColumnWidth
79
+ } = updateColumnWidths(tr, toLayout, toLayoutPos, toLayout.childCount + 1) || {};
80
+ const {
81
+ layoutColumn
82
+ } = tr.doc.type.schema.nodes || {};
83
+ const content = layoutColumn.createChecked({
84
+ width: newColumnWidth
85
+ }, sourceNode.type.name === 'layoutColumn' ? sourceNode.content : sourceNode);
86
+ tr.insert(to, content).setSelection(new NodeSelection(tr.doc.resolve(to))).scrollIntoView();
62
87
  return tr;
63
88
  };
64
89
 
@@ -134,12 +159,12 @@ export const moveToLayout = api => (from, to, options) => ({
134
159
  }
135
160
  if (toNode.type === layoutSection) {
136
161
  const toPos = options !== null && options !== void 0 && options.moveToEnd ? to + toNode.nodeSize - 1 : to + 1;
137
- return moveToExistingLayout(toNode, to, fromNodeWithoutBreakout, from, toPos, tr);
162
+ return moveToExistingLayout(toNode, to, fromNodeWithoutBreakout, from, toPos, tr, isInSameLayout($from, $to));
138
163
  } else if (toNode.type === layoutColumn) {
139
164
  const toLayout = $to.parent;
140
165
  const toLayoutPos = to - $to.parentOffset - 1;
141
166
  const toPos = options !== null && options !== void 0 && options.moveToEnd ? to + toNode.nodeSize : to;
142
- return moveToExistingLayout(toLayout, toLayoutPos, fromNodeWithoutBreakout, from, toPos, tr);
167
+ return moveToExistingLayout(toLayout, toLayoutPos, fromNodeWithoutBreakout, from, toPos, tr, isInSameLayout($from, $to));
143
168
  } else {
144
169
  let toNodeWithoutBreakout = toNode;
145
170
 
@@ -8,4 +8,5 @@ export let DIRECTION = /*#__PURE__*/function (DIRECTION) {
8
8
  }({});
9
9
  export const maxLayoutColumnSupported = () => {
10
10
  return isPreRelease2() ? 5 : 3;
11
- };
11
+ };
12
+ export const MIN_LAYOUT_COLUMN = 2;
@@ -11,7 +11,7 @@ import { DropTargetLayout } from '../ui/drop-target-layout';
11
11
  import { DropTargetV2, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET } from '../ui/drop-target-v2';
12
12
  import { isPreRelease2 } from '../utils/advanced-layouts-flags';
13
13
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
14
- import { canMoveNodeToIndex } from '../utils/validation';
14
+ import { canMoveNodeToIndex, isInSameLayout } from '../utils/validation';
15
15
  import { getNestedDepth, TYPE_DROP_TARGET_DEC, unmountDecorations } from './decorations-common';
16
16
  const IGNORE_NODES = ['tableCell', 'tableHeader', 'tableRow', 'layoutColumn', 'listItem', 'caption'];
17
17
  const PARENT_WITH_END_DROP_TARGET = ['tableCell', 'tableHeader', 'panel', 'layoutColumn', 'expand', 'nestedExpand', 'bodiedExtension'];
@@ -76,7 +76,7 @@ const getGapAndOffset = (prevNode, nextNode, parentNode) => {
76
76
  export const findDropTargetDecs = (decorations, from, to) => {
77
77
  return decorations.find(from, to, spec => spec.type === TYPE_DROP_TARGET_DEC);
78
78
  };
79
- export const createDropTargetDecoration = (pos, props, side, anchorRectCache) => {
79
+ export const createDropTargetDecoration = (pos, props, side, anchorRectCache, isSameLayout) => {
80
80
  return Decoration.widget(pos, (_, getPos) => {
81
81
  const element = document.createElement('div');
82
82
  element.setAttribute('data-blocks-drop-target-container', 'true');
@@ -92,7 +92,8 @@ export const createDropTargetDecoration = (pos, props, side, anchorRectCache) =>
92
92
  ReactDOM.render( /*#__PURE__*/createElement(DropTargetV2, {
93
93
  ...props,
94
94
  getPos,
95
- anchorRectCache
95
+ anchorRectCache,
96
+ isSameLayout
96
97
  }), element);
97
98
  } else {
98
99
  ReactDOM.render( /*#__PURE__*/createElement(DropTarget, {
@@ -128,7 +129,8 @@ export const dropTargetDecorations = (newState, api, formatMessage, activeNode,
128
129
  const docTo = to === undefined || to > POS_END_OF_DOC ? POS_END_OF_DOC : to;
129
130
  let prevNode;
130
131
  const activeNodePos = activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos;
131
- const activePMNode = typeof activeNodePos === 'number' && newState.doc.resolve(activeNodePos).nodeAfter;
132
+ const $activeNodePos = typeof activeNodePos === 'number' && newState.doc.resolve(activeNodePos);
133
+ const activePMNode = $activeNodePos && $activeNodePos.nodeAfter;
132
134
  anchorRectCache === null || anchorRectCache === void 0 ? void 0 : anchorRectCache.clear();
133
135
  const prevNodeStack = [];
134
136
  const popNodeStack = depth => {
@@ -148,12 +150,15 @@ export const dropTargetDecorations = (newState, api, formatMessage, activeNode,
148
150
  let depth = 0;
149
151
  // drop target deco at the end position
150
152
  let endPos;
153
+ const $pos = newState.doc.resolve(pos);
154
+ const isSameLayout = $activeNodePos && isInSameLayout($activeNodePos, $pos);
151
155
  if (editorExperiment('nested-dnd', true)) {
152
- depth = newState.doc.resolve(pos).depth;
156
+ depth = $pos.depth;
153
157
  if (isAdvancedLayoutsPreRelease2) {
154
- if (node.type.name === 'layoutColumn' && (parent === null || parent === void 0 ? void 0 : parent.type.name) === 'layoutSection' && (parent === null || parent === void 0 ? void 0 : parent.firstChild) !== node &&
158
+ if (node.type.name === 'layoutColumn' && (parent === null || parent === void 0 ? void 0 : parent.type.name) === 'layoutSection' && (parent === null || parent === void 0 ? void 0 : parent.firstChild) !== node && (
155
159
  // Not the first node
156
- (parent === null || parent === void 0 ? void 0 : parent.childCount) < maxLayoutColumnSupported()) {
160
+ (parent === null || parent === void 0 ? void 0 : parent.childCount) < maxLayoutColumnSupported() || isSameLayout)) {
161
+ // Add drop target for layout columns
157
162
  decs.push(createLayoutDropTargetDecoration(pos, {
158
163
  api,
159
164
  parent,
@@ -177,7 +182,7 @@ export const dropTargetDecorations = (newState, api, formatMessage, activeNode,
177
182
  }
178
183
  return shouldDescend(node); //skip over, don't consider it a valid depth
179
184
  }
180
- const canDrop = activePMNode && canMoveNodeToIndex(parent, index, activePMNode);
185
+ const canDrop = activePMNode && canMoveNodeToIndex(parent, index, activePMNode, node);
181
186
 
182
187
  //NOTE: This will block drop targets showing for nodes that are valid after transformation (i.e. expand -> nestedExpand)
183
188
  if (!canDrop && !isBlocksDragTargetDebug()) {
@@ -204,7 +209,7 @@ export const dropTargetDecorations = (newState, api, formatMessage, activeNode,
204
209
  parentNode: parent || undefined,
205
210
  formatMessage,
206
211
  dropTargetStyle: shouldShowFullHeight ? 'remainingHeight' : 'default'
207
- }, -1, anchorRectCache));
212
+ }, -1, anchorRectCache, isSameLayout));
208
213
  if (endPos !== undefined) {
209
214
  decs.push(createDropTargetDecoration(endPos, {
210
215
  api,
@@ -174,7 +174,8 @@ export const DropTargetV2 = props => {
174
174
  parentNode,
175
175
  formatMessage,
176
176
  anchorRectCache,
177
- dropTargetStyle = 'default'
177
+ dropTargetStyle = 'default',
178
+ isSameLayout
178
179
  } = props;
179
180
  const [isDraggedOver, setIsDraggedOver] = useState(false);
180
181
  const {
@@ -238,7 +239,7 @@ export const DropTargetV2 = props => {
238
239
  anchorRectCache: anchorRectCache,
239
240
  position: "lower",
240
241
  isNestedDropTarget: isNestedDropTarget
241
- }), shouldAllowInlineDropTarget(isNestedDropTarget, nextNode) && jsx(Fragment, null, jsx(InlineDropTarget, _extends({}, props, {
242
+ }), shouldAllowInlineDropTarget(isNestedDropTarget, nextNode, isSameLayout) && jsx(Fragment, null, jsx(InlineDropTarget, _extends({}, props, {
242
243
  position: "left"
243
244
  })), jsx(InlineDropTarget, _extends({}, props, {
244
245
  position: "right"
@@ -162,7 +162,7 @@ export const InlineDropTarget = ({
162
162
  }, [onDrop, setIsDraggedOver]);
163
163
  return jsx("div", {
164
164
  ref: ref,
165
- "data-test-id": `drop-target-hover-zone-${position}`,
165
+ "data-testid": `drop-target-hover-zone-${position}`,
166
166
  css: [hoverZoneCommonStyle, inlineHoverZoneRectStyle]
167
167
  }, isDraggedOver || isBlocksDragTargetDebug() ? jsx(DropIndicator, {
168
168
  edge: dropIndicatorPos
@@ -1,8 +1,12 @@
1
1
  import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
2
2
  import { maxLayoutColumnSupported } from '../consts';
3
- import { isPreRelease1 } from './advanced-layouts-flags';
3
+ import { isPreRelease1, isPreRelease2 } from './advanced-layouts-flags';
4
4
  import { isWrappedMedia } from './check-media-layout';
5
- export const shouldAllowInlineDropTarget = (isNested, node) => {
5
+ export const shouldAllowInlineDropTarget = (isNested, node,
6
+ /**
7
+ * Is the active node in the same layout as the target node
8
+ */
9
+ isSameLayout = false) => {
6
10
  if (!isPreRelease1() || isNested) {
7
11
  return false;
8
12
  }
@@ -10,7 +14,7 @@ export const shouldAllowInlineDropTarget = (isNested, node) => {
10
14
  return false;
11
15
  }
12
16
  if ((node === null || node === void 0 ? void 0 : node.type.name) === 'layoutSection') {
13
- return node.childCount < maxLayoutColumnSupported();
17
+ return node.childCount < maxLayoutColumnSupported() || isPreRelease2() && isSameLayout;
14
18
  }
15
19
  return !isEmptyParagraph(node);
16
20
  };
@@ -1,6 +1,7 @@
1
1
  import memoizeOne from 'memoize-one';
2
2
  import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
3
3
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
4
+ import { isPreRelease2 } from '../utils/advanced-layouts-flags';
4
5
  export const isInsideTable = nodeType => {
5
6
  const {
6
7
  tableCell,
@@ -20,6 +21,13 @@ export const isExpand = nodeType => {
20
21
  export const isNestedExpand = nodeType => {
21
22
  return nodeType === nodeType.schema.nodes.nestedExpand;
22
23
  };
24
+ export const isInSameLayout = ($from, $to) => {
25
+ const fromNode = $from.nodeAfter;
26
+ const toNode = $to.nodeAfter;
27
+ return !!(fromNode && toNode && fromNode.type.name === 'layoutColumn' && ['layoutSection', 'layoutColumn'].includes(toNode.type.name) && (
28
+ // fromNode can either be in the same layoutSection as toNode or is a layoutColumn inside the toNode (type layoutSection)
29
+ $from.sameParent($to) || $from.parent === toNode));
30
+ };
23
31
 
24
32
  /**
25
33
  * This function converts an expand into a nested expand,
@@ -63,7 +71,12 @@ export const memoizedTransformExpandToNestedExpand = memoizeOne(node => {
63
71
  return null;
64
72
  }
65
73
  });
66
- export function canMoveNodeToIndex(destParent, indexIntoParent, srcNode) {
74
+ export function canMoveNodeToIndex(destParent, indexIntoParent, srcNode, destNode) {
75
+ if (isPreRelease2() &&
76
+ // Allow drag layout column and drop into layout section
77
+ srcNode.type.name === 'layoutColumn' && (destNode === null || destNode === void 0 ? void 0 : destNode.type.name) === 'layoutSection') {
78
+ return true;
79
+ }
67
80
  let srcNodeType = srcNode.type;
68
81
  const parentNodeType = destParent === null || destParent === void 0 ? void 0 : destParent.type.name;
69
82
  const activeNodeType = srcNode === null || srcNode === void 0 ? void 0 : srcNode.type.name;
@@ -1,7 +1,8 @@
1
1
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
2
  import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
3
- import { maxLayoutColumnSupported } from '../consts';
3
+ import { maxLayoutColumnSupported, MIN_LAYOUT_COLUMN } from '../consts';
4
4
  import { DEFAULT_COLUMN_DISTRIBUTIONS } from '../ui/consts';
5
+ import { isInSameLayout } from '../utils/validation';
5
6
  var createNewLayout = function createNewLayout(schema, layoutContents) {
6
7
  if (layoutContents.length === 0 || layoutContents.length > maxLayoutColumnSupported()) {
7
8
  return null;
@@ -26,37 +27,60 @@ var createNewLayout = function createNewLayout(schema, layoutContents) {
26
27
  }
27
28
  return null;
28
29
  };
29
- var updateColumnWidths = function updateColumnWidths(tr, layoutNode, layoutNodePos, newColumnWidth) {
30
+ var updateColumnWidths = function updateColumnWidths(tr, layoutNode, layoutNodePos, childCount) {
31
+ var newColumnWidth = DEFAULT_COLUMN_DISTRIBUTIONS[childCount];
30
32
  if (newColumnWidth) {
31
33
  layoutNode.content.forEach(function (node, offset) {
32
34
  if (node.type.name === 'layoutColumn') {
33
- tr = tr.setNodeAttribute(layoutNodePos + offset + 1, 'width', newColumnWidth);
35
+ tr.setNodeAttribute(layoutNodePos + offset + 1, 'width', newColumnWidth);
34
36
  }
35
37
  });
36
38
  }
37
- return tr;
39
+ return {
40
+ newColumnWidth: newColumnWidth,
41
+ tr: tr
42
+ };
38
43
  };
39
-
40
- /**
41
- * Insert a node into an existing layout at position `to` and delete the node
42
- */
43
- var moveNode = function moveNode(from, to, newNode, sourceNodeSize, tr) {
44
- tr.insert(to, newNode).setSelection(new NodeSelection(tr.doc.resolve(to))).scrollIntoView();
45
- var mappedFrom = tr.mapping.map(from);
46
- var mappedFromEnd = mappedFrom + sourceNodeSize;
47
- tr.delete(mappedFrom, mappedFromEnd);
44
+ var moveToExistingLayout = function moveToExistingLayout(toLayout, toLayoutPos, sourceNode, from, to, tr, isSameLayout) {
45
+ if (isSameLayout) {
46
+ // reorder columns
47
+ tr.delete(from, from + sourceNode.nodeSize);
48
+ var mappedTo = tr.mapping.map(to);
49
+ tr.insert(mappedTo, sourceNode).setSelection(new NodeSelection(tr.doc.resolve(mappedTo))).scrollIntoView();
50
+ } else if (toLayout.childCount < maxLayoutColumnSupported()) {
51
+ insertToDestination(tr, to, sourceNode, toLayout, toLayoutPos);
52
+ var mappedFrom = tr.mapping.map(from);
53
+ removeFromSource(tr, tr.doc.resolve(mappedFrom));
54
+ }
48
55
  return tr;
49
56
  };
50
- var moveToExistingLayout = function moveToExistingLayout(toLayout, toLayoutPos, sourceNode, from, to, tr) {
51
- if (toLayout.childCount < maxLayoutColumnSupported()) {
52
- var newColumnWidth = DEFAULT_COLUMN_DISTRIBUTIONS[toLayout.childCount + 1];
53
- updateColumnWidths(tr, toLayout, toLayoutPos, newColumnWidth);
54
- var _ref2 = tr.doc.type.schema.nodes || {},
55
- layoutColumn = _ref2.layoutColumn;
56
- moveNode(from, to, layoutColumn.create({
57
- width: newColumnWidth
58
- }, sourceNode), sourceNode.nodeSize, tr);
57
+ var removeFromSource = function removeFromSource(tr, $from) {
58
+ var sourceNode = $from.nodeAfter;
59
+ var sourceParent = $from.parent;
60
+ if (!sourceNode) {
61
+ return tr;
62
+ }
63
+ var sourceNodeEndPos = $from.pos + sourceNode.nodeSize;
64
+ if (sourceNode.type.name === 'layoutColumn') {
65
+ if (sourceParent.childCount === MIN_LAYOUT_COLUMN) {
66
+ tr.delete($from.pos + 1, sourceNodeEndPos - 1);
67
+ return tr;
68
+ } else {
69
+ updateColumnWidths(tr, $from.parent, $from.before($from.depth), sourceParent.childCount - 1);
70
+ }
59
71
  }
72
+ tr.delete($from.pos, sourceNodeEndPos);
73
+ return tr;
74
+ };
75
+ var insertToDestination = function insertToDestination(tr, to, sourceNode, toLayout, toLayoutPos) {
76
+ var _ref2 = updateColumnWidths(tr, toLayout, toLayoutPos, toLayout.childCount + 1) || {},
77
+ newColumnWidth = _ref2.newColumnWidth;
78
+ var _ref3 = tr.doc.type.schema.nodes || {},
79
+ layoutColumn = _ref3.layoutColumn;
80
+ var content = layoutColumn.createChecked({
81
+ width: newColumnWidth
82
+ }, sourceNode.type.name === 'layoutColumn' ? sourceNode.content : sourceNode);
83
+ tr.insert(to, content).setSelection(new NodeSelection(tr.doc.resolve(to))).scrollIntoView();
60
84
  return tr;
61
85
  };
62
86
 
@@ -68,10 +92,10 @@ var canMoveToLayout = function canMoveToLayout(from, to, tr) {
68
92
  if (from === to) {
69
93
  return;
70
94
  }
71
- var _ref3 = tr.doc.type.schema.nodes || {},
72
- layoutSection = _ref3.layoutSection,
73
- layoutColumn = _ref3.layoutColumn,
74
- doc = _ref3.doc;
95
+ var _ref4 = tr.doc.type.schema.nodes || {},
96
+ layoutSection = _ref4.layoutSection,
97
+ layoutColumn = _ref4.layoutColumn,
98
+ doc = _ref4.doc;
75
99
 
76
100
  // layout plugin does not exist
77
101
  if (!layoutSection || !layoutColumn) {
@@ -100,8 +124,8 @@ var canMoveToLayout = function canMoveToLayout(from, to, tr) {
100
124
  };
101
125
  export var moveToLayout = function moveToLayout(api) {
102
126
  return function (from, to, options) {
103
- return function (_ref4) {
104
- var tr = _ref4.tr;
127
+ return function (_ref5) {
128
+ var tr = _ref5.tr;
105
129
  var canMove = canMoveToLayout(from, to, tr);
106
130
  if (!canMove) {
107
131
  return tr;
@@ -110,11 +134,11 @@ export var moveToLayout = function moveToLayout(api) {
110
134
  fromNode = canMove.fromNode,
111
135
  $from = canMove.$from,
112
136
  $to = canMove.$to;
113
- var _ref5 = tr.doc.type.schema.nodes || {},
114
- layoutSection = _ref5.layoutSection,
115
- layoutColumn = _ref5.layoutColumn;
116
- var _ref6 = tr.doc.type.schema.marks || {},
117
- breakout = _ref6.breakout;
137
+ var _ref6 = tr.doc.type.schema.nodes || {},
138
+ layoutSection = _ref6.layoutSection,
139
+ layoutColumn = _ref6.layoutColumn;
140
+ var _ref7 = tr.doc.type.schema.marks || {},
141
+ breakout = _ref7.breakout;
118
142
  var fromNodeWithoutBreakout = fromNode;
119
143
 
120
144
  // remove breakout from node;
@@ -130,12 +154,12 @@ export var moveToLayout = function moveToLayout(api) {
130
154
  }
131
155
  if (toNode.type === layoutSection) {
132
156
  var toPos = options !== null && options !== void 0 && options.moveToEnd ? to + toNode.nodeSize - 1 : to + 1;
133
- return moveToExistingLayout(toNode, to, fromNodeWithoutBreakout, from, toPos, tr);
157
+ return moveToExistingLayout(toNode, to, fromNodeWithoutBreakout, from, toPos, tr, isInSameLayout($from, $to));
134
158
  } else if (toNode.type === layoutColumn) {
135
159
  var toLayout = $to.parent;
136
160
  var toLayoutPos = to - $to.parentOffset - 1;
137
161
  var _toPos = options !== null && options !== void 0 && options.moveToEnd ? to + toNode.nodeSize : to;
138
- return moveToExistingLayout(toLayout, toLayoutPos, fromNodeWithoutBreakout, from, _toPos, tr);
162
+ return moveToExistingLayout(toLayout, toLayoutPos, fromNodeWithoutBreakout, from, _toPos, tr, isInSameLayout($from, $to));
139
163
  } else {
140
164
  var toNodeWithoutBreakout = toNode;
141
165
 
@@ -8,4 +8,5 @@ export var DIRECTION = /*#__PURE__*/function (DIRECTION) {
8
8
  }({});
9
9
  export var maxLayoutColumnSupported = function maxLayoutColumnSupported() {
10
10
  return isPreRelease2() ? 5 : 3;
11
- };
11
+ };
12
+ export var MIN_LAYOUT_COLUMN = 2;
@@ -14,7 +14,7 @@ import { DropTargetLayout } from '../ui/drop-target-layout';
14
14
  import { DropTargetV2, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET } from '../ui/drop-target-v2';
15
15
  import { isPreRelease2 } from '../utils/advanced-layouts-flags';
16
16
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
17
- import { canMoveNodeToIndex } from '../utils/validation';
17
+ import { canMoveNodeToIndex, isInSameLayout } from '../utils/validation';
18
18
  import { getNestedDepth, TYPE_DROP_TARGET_DEC, unmountDecorations } from './decorations-common';
19
19
  var IGNORE_NODES = ['tableCell', 'tableHeader', 'tableRow', 'layoutColumn', 'listItem', 'caption'];
20
20
  var PARENT_WITH_END_DROP_TARGET = ['tableCell', 'tableHeader', 'panel', 'layoutColumn', 'expand', 'nestedExpand', 'bodiedExtension'];
@@ -81,7 +81,7 @@ export var findDropTargetDecs = function findDropTargetDecs(decorations, from, t
81
81
  return spec.type === TYPE_DROP_TARGET_DEC;
82
82
  });
83
83
  };
84
- export var createDropTargetDecoration = function createDropTargetDecoration(pos, props, side, anchorRectCache) {
84
+ export var createDropTargetDecoration = function createDropTargetDecoration(pos, props, side, anchorRectCache, isSameLayout) {
85
85
  return Decoration.widget(pos, function (_, getPos) {
86
86
  var element = document.createElement('div');
87
87
  element.setAttribute('data-blocks-drop-target-container', 'true');
@@ -95,7 +95,8 @@ export var createDropTargetDecoration = function createDropTargetDecoration(pos,
95
95
  element.style.setProperty('display', 'block');
96
96
  ReactDOM.render( /*#__PURE__*/createElement(DropTargetV2, _objectSpread(_objectSpread({}, props), {}, {
97
97
  getPos: getPos,
98
- anchorRectCache: anchorRectCache
98
+ anchorRectCache: anchorRectCache,
99
+ isSameLayout: isSameLayout
99
100
  })), element);
100
101
  } else {
101
102
  ReactDOM.render( /*#__PURE__*/createElement(DropTarget, _objectSpread(_objectSpread({}, props), {}, {
@@ -129,7 +130,8 @@ export var dropTargetDecorations = function dropTargetDecorations(newState, api,
129
130
  var docTo = to === undefined || to > POS_END_OF_DOC ? POS_END_OF_DOC : to;
130
131
  var prevNode;
131
132
  var activeNodePos = activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos;
132
- var activePMNode = typeof activeNodePos === 'number' && newState.doc.resolve(activeNodePos).nodeAfter;
133
+ var $activeNodePos = typeof activeNodePos === 'number' && newState.doc.resolve(activeNodePos);
134
+ var activePMNode = $activeNodePos && $activeNodePos.nodeAfter;
133
135
  anchorRectCache === null || anchorRectCache === void 0 || anchorRectCache.clear();
134
136
  var prevNodeStack = [];
135
137
  var popNodeStack = function popNodeStack(depth) {
@@ -149,12 +151,15 @@ export var dropTargetDecorations = function dropTargetDecorations(newState, api,
149
151
  var depth = 0;
150
152
  // drop target deco at the end position
151
153
  var endPos;
154
+ var $pos = newState.doc.resolve(pos);
155
+ var isSameLayout = $activeNodePos && isInSameLayout($activeNodePos, $pos);
152
156
  if (editorExperiment('nested-dnd', true)) {
153
- depth = newState.doc.resolve(pos).depth;
157
+ depth = $pos.depth;
154
158
  if (isAdvancedLayoutsPreRelease2) {
155
- if (node.type.name === 'layoutColumn' && (parent === null || parent === void 0 ? void 0 : parent.type.name) === 'layoutSection' && (parent === null || parent === void 0 ? void 0 : parent.firstChild) !== node &&
159
+ if (node.type.name === 'layoutColumn' && (parent === null || parent === void 0 ? void 0 : parent.type.name) === 'layoutSection' && (parent === null || parent === void 0 ? void 0 : parent.firstChild) !== node && (
156
160
  // Not the first node
157
- (parent === null || parent === void 0 ? void 0 : parent.childCount) < maxLayoutColumnSupported()) {
161
+ (parent === null || parent === void 0 ? void 0 : parent.childCount) < maxLayoutColumnSupported() || isSameLayout)) {
162
+ // Add drop target for layout columns
158
163
  decs.push(createLayoutDropTargetDecoration(pos, {
159
164
  api: api,
160
165
  parent: parent,
@@ -178,7 +183,7 @@ export var dropTargetDecorations = function dropTargetDecorations(newState, api,
178
183
  }
179
184
  return shouldDescend(node); //skip over, don't consider it a valid depth
180
185
  }
181
- var canDrop = activePMNode && canMoveNodeToIndex(parent, index, activePMNode);
186
+ var canDrop = activePMNode && canMoveNodeToIndex(parent, index, activePMNode, node);
182
187
 
183
188
  //NOTE: This will block drop targets showing for nodes that are valid after transformation (i.e. expand -> nestedExpand)
184
189
  if (!canDrop && !isBlocksDragTargetDebug()) {
@@ -205,7 +210,7 @@ export var dropTargetDecorations = function dropTargetDecorations(newState, api,
205
210
  parentNode: parent || undefined,
206
211
  formatMessage: formatMessage,
207
212
  dropTargetStyle: shouldShowFullHeight ? 'remainingHeight' : 'default'
208
- }, -1, anchorRectCache));
213
+ }, -1, anchorRectCache, isSameLayout));
209
214
  if (endPos !== undefined) {
210
215
  decs.push(createDropTargetDecoration(endPos, {
211
216
  api: api,
@@ -179,7 +179,8 @@ export var DropTargetV2 = function DropTargetV2(props) {
179
179
  formatMessage = props.formatMessage,
180
180
  anchorRectCache = props.anchorRectCache,
181
181
  _props$dropTargetStyl = props.dropTargetStyle,
182
- dropTargetStyle = _props$dropTargetStyl === void 0 ? 'default' : _props$dropTargetStyl;
182
+ dropTargetStyle = _props$dropTargetStyl === void 0 ? 'default' : _props$dropTargetStyl,
183
+ isSameLayout = props.isSameLayout;
183
184
  var _useState = useState(false),
184
185
  _useState2 = _slicedToArray(_useState, 2),
185
186
  isDraggedOver = _useState2[0],
@@ -246,7 +247,7 @@ export var DropTargetV2 = function DropTargetV2(props) {
246
247
  anchorRectCache: anchorRectCache,
247
248
  position: "lower",
248
249
  isNestedDropTarget: isNestedDropTarget
249
- }), shouldAllowInlineDropTarget(isNestedDropTarget, nextNode) && jsx(Fragment, null, jsx(InlineDropTarget, _extends({}, props, {
250
+ }), shouldAllowInlineDropTarget(isNestedDropTarget, nextNode, isSameLayout) && jsx(Fragment, null, jsx(InlineDropTarget, _extends({}, props, {
250
251
  position: "left"
251
252
  })), jsx(InlineDropTarget, _extends({}, props, {
252
253
  position: "right"
@@ -164,7 +164,7 @@ export var InlineDropTarget = function InlineDropTarget(_ref) {
164
164
  }, [onDrop, setIsDraggedOver]);
165
165
  return jsx("div", {
166
166
  ref: ref,
167
- "data-test-id": "drop-target-hover-zone-".concat(position),
167
+ "data-testid": "drop-target-hover-zone-".concat(position),
168
168
  css: [hoverZoneCommonStyle, inlineHoverZoneRectStyle]
169
169
  }, isDraggedOver || isBlocksDragTargetDebug() ? jsx(DropIndicator, {
170
170
  edge: dropIndicatorPos
@@ -1,8 +1,9 @@
1
1
  import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
2
2
  import { maxLayoutColumnSupported } from '../consts';
3
- import { isPreRelease1 } from './advanced-layouts-flags';
3
+ import { isPreRelease1, isPreRelease2 } from './advanced-layouts-flags';
4
4
  import { isWrappedMedia } from './check-media-layout';
5
5
  export var shouldAllowInlineDropTarget = function shouldAllowInlineDropTarget(isNested, node) {
6
+ var isSameLayout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
6
7
  if (!isPreRelease1() || isNested) {
7
8
  return false;
8
9
  }
@@ -10,7 +11,7 @@ export var shouldAllowInlineDropTarget = function shouldAllowInlineDropTarget(is
10
11
  return false;
11
12
  }
12
13
  if ((node === null || node === void 0 ? void 0 : node.type.name) === 'layoutSection') {
13
- return node.childCount < maxLayoutColumnSupported();
14
+ return node.childCount < maxLayoutColumnSupported() || isPreRelease2() && isSameLayout;
14
15
  }
15
16
  return !isEmptyParagraph(node);
16
17
  };
@@ -1,6 +1,7 @@
1
1
  import memoizeOne from 'memoize-one';
2
2
  import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
3
3
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
4
+ import { isPreRelease2 } from '../utils/advanced-layouts-flags';
4
5
  export var isInsideTable = function isInsideTable(nodeType) {
5
6
  var _nodeType$schema$node = nodeType.schema.nodes,
6
7
  tableCell = _nodeType$schema$node.tableCell,
@@ -19,6 +20,13 @@ export var isExpand = function isExpand(nodeType) {
19
20
  export var isNestedExpand = function isNestedExpand(nodeType) {
20
21
  return nodeType === nodeType.schema.nodes.nestedExpand;
21
22
  };
23
+ export var isInSameLayout = function isInSameLayout($from, $to) {
24
+ var fromNode = $from.nodeAfter;
25
+ var toNode = $to.nodeAfter;
26
+ return !!(fromNode && toNode && fromNode.type.name === 'layoutColumn' && ['layoutSection', 'layoutColumn'].includes(toNode.type.name) && (
27
+ // fromNode can either be in the same layoutSection as toNode or is a layoutColumn inside the toNode (type layoutSection)
28
+ $from.sameParent($to) || $from.parent === toNode));
29
+ };
22
30
 
23
31
  /**
24
32
  * This function converts an expand into a nested expand,
@@ -61,7 +69,12 @@ export var memoizedTransformExpandToNestedExpand = memoizeOne(function (node) {
61
69
  return null;
62
70
  }
63
71
  });
64
- export function canMoveNodeToIndex(destParent, indexIntoParent, srcNode) {
72
+ export function canMoveNodeToIndex(destParent, indexIntoParent, srcNode, destNode) {
73
+ if (isPreRelease2() &&
74
+ // Allow drag layout column and drop into layout section
75
+ srcNode.type.name === 'layoutColumn' && (destNode === null || destNode === void 0 ? void 0 : destNode.type.name) === 'layoutSection') {
76
+ return true;
77
+ }
65
78
  var srcNodeType = srcNode.type;
66
79
  var parentNodeType = destParent === null || destParent === void 0 ? void 0 : destParent.type.name;
67
80
  var activeNodeType = srcNode === null || srcNode === void 0 ? void 0 : srcNode.type.name;
@@ -5,3 +5,4 @@ export declare enum DIRECTION {
5
5
  RIGHT = "right"
6
6
  }
7
7
  export declare const maxLayoutColumnSupported: () => 5 | 3;
8
+ export declare const MIN_LAYOUT_COLUMN = 2;
@@ -14,6 +14,6 @@ import { type AnchorRectCache } from '../utils/anchor-utils';
14
14
  * @returns
15
15
  */
16
16
  export declare const findDropTargetDecs: (decorations: DecorationSet, from?: number, to?: number) => Decoration[];
17
- export declare const createDropTargetDecoration: (pos: number, props: Omit<DropTargetProps, 'getPos'>, side?: number, anchorRectCache?: AnchorRectCache) => Decoration;
17
+ export declare const createDropTargetDecoration: (pos: number, props: Omit<DropTargetProps, 'getPos'>, side?: number, anchorRectCache?: AnchorRectCache, isSameLayout?: boolean) => Decoration;
18
18
  export declare const createLayoutDropTargetDecoration: (pos: number, props: Omit<DropTargetLayoutProps, 'getPos'>) => Decoration;
19
19
  export declare const dropTargetDecorations: (newState: EditorState, api: ExtractInjectionAPI<BlockControlsPlugin>, formatMessage: IntlShape['formatMessage'], activeNode?: ActiveNode, anchorRectCache?: AnchorRectCache, from?: number, to?: number) => Decoration[];
@@ -5,4 +5,5 @@ export declare const EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET = "--editor-blo
5
5
  export declare const EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP = "--editor-block-controls-drop-indicator-gap";
6
6
  export declare const DropTargetV2: (props: DropTargetProps & {
7
7
  anchorRectCache?: AnchorRectCache | undefined;
8
+ isSameLayout?: boolean | undefined;
8
9
  }) => jsx.JSX.Element;
@@ -1,2 +1,2 @@
1
1
  import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
- export declare const shouldAllowInlineDropTarget: (isNested: boolean, node?: PMNode) => boolean;
2
+ export declare const shouldAllowInlineDropTarget: (isNested: boolean, node?: PMNode, isSameLayout?: boolean) => boolean;
@@ -1,10 +1,11 @@
1
1
  import { Slice } from '@atlaskit/editor-prosemirror/model';
2
- import type { NodeType, Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
+ import type { NodeType, Node as PMNode, ResolvedPos } from '@atlaskit/editor-prosemirror/model';
3
3
  export declare const isInsideTable: (nodeType: NodeType) => Boolean;
4
4
  export declare const isLayoutColumn: (nodeType: NodeType) => Boolean;
5
5
  export declare const isDoc: (nodeType: NodeType) => Boolean;
6
6
  export declare const isExpand: (nodeType: NodeType) => Boolean;
7
7
  export declare const isNestedExpand: (nodeType: NodeType) => Boolean;
8
+ export declare const isInSameLayout: ($from: ResolvedPos, $to: ResolvedPos) => boolean;
8
9
  /**
9
10
  * This function converts an expand into a nested expand,
10
11
  * although it may fail based on the expand's content.
@@ -15,4 +16,4 @@ export declare const isNestedExpand: (nodeType: NodeType) => Boolean;
15
16
  export declare const transformExpandToNestedExpand: (expandNode: PMNode) => PMNode | null;
16
17
  export declare const transformSliceExpandToNestedExpand: (slice: Slice) => Slice | null;
17
18
  export declare const memoizedTransformExpandToNestedExpand: import("memoize-one").MemoizedFn<(node: PMNode) => PMNode | null>;
18
- export declare function canMoveNodeToIndex(destParent: PMNode, indexIntoParent: number, srcNode: PMNode): boolean;
19
+ export declare function canMoveNodeToIndex(destParent: PMNode, indexIntoParent: number, srcNode: PMNode, destNode?: PMNode): boolean;
@@ -5,3 +5,4 @@ export declare enum DIRECTION {
5
5
  RIGHT = "right"
6
6
  }
7
7
  export declare const maxLayoutColumnSupported: () => 5 | 3;
8
+ export declare const MIN_LAYOUT_COLUMN = 2;
@@ -14,6 +14,6 @@ import { type AnchorRectCache } from '../utils/anchor-utils';
14
14
  * @returns
15
15
  */
16
16
  export declare const findDropTargetDecs: (decorations: DecorationSet, from?: number, to?: number) => Decoration[];
17
- export declare const createDropTargetDecoration: (pos: number, props: Omit<DropTargetProps, 'getPos'>, side?: number, anchorRectCache?: AnchorRectCache) => Decoration;
17
+ export declare const createDropTargetDecoration: (pos: number, props: Omit<DropTargetProps, 'getPos'>, side?: number, anchorRectCache?: AnchorRectCache, isSameLayout?: boolean) => Decoration;
18
18
  export declare const createLayoutDropTargetDecoration: (pos: number, props: Omit<DropTargetLayoutProps, 'getPos'>) => Decoration;
19
19
  export declare const dropTargetDecorations: (newState: EditorState, api: ExtractInjectionAPI<BlockControlsPlugin>, formatMessage: IntlShape['formatMessage'], activeNode?: ActiveNode, anchorRectCache?: AnchorRectCache, from?: number, to?: number) => Decoration[];
@@ -5,4 +5,5 @@ export declare const EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET = "--editor-blo
5
5
  export declare const EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP = "--editor-block-controls-drop-indicator-gap";
6
6
  export declare const DropTargetV2: (props: DropTargetProps & {
7
7
  anchorRectCache?: AnchorRectCache | undefined;
8
+ isSameLayout?: boolean | undefined;
8
9
  }) => jsx.JSX.Element;
@@ -1,2 +1,2 @@
1
1
  import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
- export declare const shouldAllowInlineDropTarget: (isNested: boolean, node?: PMNode) => boolean;
2
+ export declare const shouldAllowInlineDropTarget: (isNested: boolean, node?: PMNode, isSameLayout?: boolean) => boolean;
@@ -1,10 +1,11 @@
1
1
  import { Slice } from '@atlaskit/editor-prosemirror/model';
2
- import type { NodeType, Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
+ import type { NodeType, Node as PMNode, ResolvedPos } from '@atlaskit/editor-prosemirror/model';
3
3
  export declare const isInsideTable: (nodeType: NodeType) => Boolean;
4
4
  export declare const isLayoutColumn: (nodeType: NodeType) => Boolean;
5
5
  export declare const isDoc: (nodeType: NodeType) => Boolean;
6
6
  export declare const isExpand: (nodeType: NodeType) => Boolean;
7
7
  export declare const isNestedExpand: (nodeType: NodeType) => Boolean;
8
+ export declare const isInSameLayout: ($from: ResolvedPos, $to: ResolvedPos) => boolean;
8
9
  /**
9
10
  * This function converts an expand into a nested expand,
10
11
  * although it may fail based on the expand's content.
@@ -15,4 +16,4 @@ export declare const isNestedExpand: (nodeType: NodeType) => Boolean;
15
16
  export declare const transformExpandToNestedExpand: (expandNode: PMNode) => PMNode | null;
16
17
  export declare const transformSliceExpandToNestedExpand: (slice: Slice) => Slice | null;
17
18
  export declare const memoizedTransformExpandToNestedExpand: import("memoize-one").MemoizedFn<(node: PMNode) => PMNode | null>;
18
- export declare function canMoveNodeToIndex(destParent: PMNode, indexIntoParent: number, srcNode: PMNode): boolean;
19
+ export declare function canMoveNodeToIndex(destParent: PMNode, indexIntoParent: number, srcNode: PMNode, destNode?: PMNode): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-controls",
3
- "version": "2.13.10",
3
+ "version": "2.13.12",
4
4
  "description": "Block controls plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@atlaskit/adf-schema": "^44.2.0",
34
- "@atlaskit/editor-common": "^94.16.0",
34
+ "@atlaskit/editor-common": "^94.20.0",
35
35
  "@atlaskit/editor-plugin-accessibility-utils": "^1.2.0",
36
36
  "@atlaskit/editor-plugin-analytics": "^1.10.0",
37
37
  "@atlaskit/editor-plugin-editor-disabled": "^1.3.0",
@@ -48,7 +48,7 @@
48
48
  "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^1.1.0",
49
49
  "@atlaskit/primitives": "^13.1.0",
50
50
  "@atlaskit/theme": "^14.0.0",
51
- "@atlaskit/tmp-editor-statsig": "^2.12.0",
51
+ "@atlaskit/tmp-editor-statsig": "^2.14.0",
52
52
  "@atlaskit/tokens": "^2.2.0",
53
53
  "@atlaskit/tooltip": "^18.9.0",
54
54
  "@babel/runtime": "^7.0.0",