@atlaskit/editor-plugin-block-controls 2.1.11 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cjs/commands/move-node.js +39 -14
  3. package/dist/cjs/commands/show-drag-handle.js +39 -6
  4. package/dist/cjs/consts.js +2 -0
  5. package/dist/cjs/pm-plugins/handle-mouse-over.js +1 -1
  6. package/dist/cjs/pm-plugins/keymap.js +2 -0
  7. package/dist/cjs/ui/drag-handle.js +20 -0
  8. package/dist/cjs/utils/getNestedNodePosition.js +27 -0
  9. package/dist/cjs/utils/index.js +8 -1
  10. package/dist/es2019/commands/move-node.js +33 -8
  11. package/dist/es2019/commands/show-drag-handle.js +38 -2
  12. package/dist/es2019/consts.js +2 -0
  13. package/dist/es2019/pm-plugins/handle-mouse-over.js +1 -1
  14. package/dist/es2019/pm-plugins/keymap.js +3 -1
  15. package/dist/es2019/ui/drag-handle.js +22 -3
  16. package/dist/es2019/utils/getNestedNodePosition.js +23 -0
  17. package/dist/es2019/utils/index.js +2 -1
  18. package/dist/esm/commands/move-node.js +33 -8
  19. package/dist/esm/commands/show-drag-handle.js +39 -6
  20. package/dist/esm/consts.js +2 -0
  21. package/dist/esm/pm-plugins/handle-mouse-over.js +1 -1
  22. package/dist/esm/pm-plugins/keymap.js +3 -1
  23. package/dist/esm/ui/drag-handle.js +22 -2
  24. package/dist/esm/utils/getNestedNodePosition.js +21 -0
  25. package/dist/esm/utils/index.js +2 -1
  26. package/dist/types/commands/show-drag-handle.d.ts +1 -1
  27. package/dist/types/consts.d.ts +3 -1
  28. package/dist/types/utils/getNestedNodePosition.d.ts +2 -0
  29. package/dist/types/utils/index.d.ts +1 -0
  30. package/dist/types-ts4.5/commands/show-drag-handle.d.ts +1 -1
  31. package/dist/types-ts4.5/consts.d.ts +3 -1
  32. package/dist/types-ts4.5/utils/getNestedNodePosition.d.ts +2 -0
  33. package/dist/types-ts4.5/utils/index.d.ts +1 -0
  34. package/package.json +7 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 2.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#150591](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/150591)
8
+ [`13337452246bc`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/13337452246bc) -
9
+ support a11y to move various node types with shortcut
10
+
11
+ ## 2.2.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [#148229](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/148229)
16
+ [`657f160f0cfc0`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/657f160f0cfc0) -
17
+ Add a11y support on moving nested elements
18
+
19
+ ### Patch Changes
20
+
21
+ - [#137506](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/137506)
22
+ [`bc1742c9fd32e`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/bc1742c9fd32e) -
23
+ ED-24902: Fix to only check when to hide drag handle on doc level (behind
24
+ confluence_frontend_page_title_enter_improvements)
25
+ - Updated dependencies
26
+
3
27
  ## 2.1.11
4
28
 
5
29
  ### Patch Changes
@@ -11,12 +11,13 @@ var _messages = require("@atlaskit/editor-common/messages");
11
11
  var _selection = require("@atlaskit/editor-common/selection");
12
12
  var _transforms = require("@atlaskit/editor-common/transforms");
13
13
  var _utils = require("@atlaskit/editor-common/utils");
14
- var _utils2 = require("@atlaskit/editor-tables/utils");
14
+ var _utils2 = require("@atlaskit/editor-prosemirror/utils");
15
+ var _utils3 = require("@atlaskit/editor-tables/utils");
15
16
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
16
17
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
17
18
  var _consts = require("../consts");
18
19
  var _main = require("../pm-plugins/main");
19
- var _utils3 = require("../utils");
20
+ var _utils4 = require("../utils");
20
21
  var _validation = require("../utils/validation");
21
22
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
22
23
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -46,7 +47,7 @@ function transformSourceSlice(nodeCopy, destType) {
46
47
  *
47
48
  * @returns the start position of a node if the node can be moved, otherwise -1
48
49
  */
49
- var getCurrentNodePos = function getCurrentNodePos(state) {
50
+ var getCurrentNodePos = function getCurrentNodePos(state, isParentNodeOfTypeLayout) {
50
51
  var _activeNode$handleOpt;
51
52
  var selection = state.selection;
52
53
  var _ref = _main.key.getState(state) || {},
@@ -57,32 +58,53 @@ var getCurrentNodePos = function getCurrentNodePos(state) {
57
58
  if (activeNode && (_activeNode$handleOpt = activeNode.handleOptions) !== null && _activeNode$handleOpt !== void 0 && _activeNode$handleOpt.isFocused) {
58
59
  // 1. drag handle of the node is focused
59
60
  currentNodePos = activeNode.pos;
60
- } else if ((0, _utils2.isInTable)(state)) {
61
- if ((0, _utils2.isTableSelected)(selection)) {
61
+ } else if ((0, _utils3.isInTable)(state)) {
62
+ if ((0, _utils3.isTableSelected)(selection)) {
62
63
  var _findTable$pos, _findTable;
63
64
  // We only move table node if it's fully selected
64
65
  // to avoid shortcut collision with table drag and drop
65
- currentNodePos = (_findTable$pos = (_findTable = (0, _utils2.findTable)(selection)) === null || _findTable === void 0 ? void 0 : _findTable.pos) !== null && _findTable$pos !== void 0 ? _findTable$pos : currentNodePos;
66
+ currentNodePos = (_findTable$pos = (_findTable = (0, _utils3.findTable)(selection)) === null || _findTable === void 0 ? void 0 : _findTable.pos) !== null && _findTable$pos !== void 0 ? _findTable$pos : currentNodePos;
66
67
  }
67
68
  } else if (!(state.selection instanceof _selection.GapCursorSelection)) {
68
69
  // 2. caret cursor is inside the node
69
70
  // 3. the start of the selection is inside the node
70
71
  currentNodePos = selection.$from.before(1);
72
+ if (selection.$from.depth > 0 && (0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y')) {
73
+ currentNodePos = (0, _utils4.getNestedNodePosition)(state);
74
+ }
71
75
  }
72
76
  return currentNodePos;
73
77
  };
74
78
  var moveNodeViaShortcut = exports.moveNodeViaShortcut = function moveNodeViaShortcut(api, direction, formatMessage) {
75
79
  return function (state) {
76
- var currentNodePos = getCurrentNodePos(state);
80
+ var isParentNodeOfTypeLayout;
81
+ if ((0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y')) {
82
+ isParentNodeOfTypeLayout = !!(0, _utils2.findParentNodeOfType)([state.schema.nodes.layoutSection])(state.selection);
83
+ }
84
+ var currentNodePos = getCurrentNodePos(state, isParentNodeOfTypeLayout);
77
85
  if (currentNodePos > -1) {
78
86
  var _state$doc$nodeAt;
79
87
  var $pos = state.doc.resolve(currentNodePos);
80
88
  var moveToPos = -1;
81
- if (direction === _consts.DIRECTION.UP) {
82
- var nodeBefore = $pos.nodeBefore;
83
- if (nodeBefore) {
84
- moveToPos = currentNodePos - nodeBefore.nodeSize;
89
+ var nodeIndex = $pos.index();
90
+ if (direction === _consts.DIRECTION.LEFT && (0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y')) {
91
+ if ($pos.depth < 2 || !isParentNodeOfTypeLayout) {
92
+ return false;
85
93
  }
94
+
95
+ // get the previous layoutSection node
96
+ var index = $pos.index($pos.depth - 1);
97
+ var grandParent = $pos.node($pos.depth - 1);
98
+ var previousNode = grandParent ? grandParent.maybeChild(index - 1) : null;
99
+ moveToPos = $pos.start() - ((previousNode === null || previousNode === void 0 ? void 0 : previousNode.nodeSize) || 1);
100
+ } else if (direction === _consts.DIRECTION.RIGHT && (0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y')) {
101
+ if ($pos.depth < 2 || !isParentNodeOfTypeLayout) {
102
+ return false;
103
+ }
104
+ moveToPos = $pos.after($pos.depth) + 1;
105
+ } else if (direction === _consts.DIRECTION.UP) {
106
+ var nodeBefore = $pos.depth > 1 && nodeIndex === 0 && (0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y') ? $pos.node($pos.depth) : $pos.nodeBefore;
107
+ moveToPos = $pos.depth > 1 && nodeIndex === 0 && (0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y') ? $pos.before($pos.depth) - 1 : nodeBefore ? currentNodePos - nodeBefore.nodeSize : moveToPos;
86
108
  } else {
87
109
  var endOfDoc = $pos.end();
88
110
  var nodeAfterPos = $pos.posAtIndex($pos.index() + 1);
@@ -93,7 +115,10 @@ var moveNodeViaShortcut = exports.moveNodeViaShortcut = function moveNodeViaShor
93
115
  }
94
116
  }
95
117
  var nodeType = (_state$doc$nodeAt = state.doc.nodeAt(currentNodePos)) === null || _state$doc$nodeAt === void 0 ? void 0 : _state$doc$nodeAt.type.name;
96
- if (moveToPos > -1) {
118
+
119
+ // only move the node if the destination is at the same depth, not support moving a nested node to a parent node
120
+ var shouldMoveNode = (0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y') ? moveToPos > -1 && $pos.depth === state.doc.resolve(moveToPos).depth : moveToPos > -1;
121
+ if (shouldMoveNode) {
97
122
  var _api$core;
98
123
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref2) {
99
124
  var tr = _ref2.tr;
@@ -109,7 +134,7 @@ var moveNodeViaShortcut = exports.moveNodeViaShortcut = function moveNodeViaShor
109
134
  // If the node is first/last one, only select the node
110
135
  api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(function (_ref3) {
111
136
  var tr = _ref3.tr;
112
- (0, _utils3.selectNode)(tr, currentNodePos, nodeType);
137
+ (0, _utils4.selectNode)(tr, currentNodePos, nodeType);
113
138
  tr.scrollIntoView();
114
139
  return tr;
115
140
  });
@@ -164,7 +189,7 @@ var moveNode = exports.moveNode = function moveNode(api) {
164
189
  mappedTo = tr.mapping.map(to);
165
190
  tr.insert(mappedTo, _nodeCopy); // insert the content at the new position
166
191
  }
167
- tr = (0, _utils3.selectNode)(tr, mappedTo, node.type.name);
192
+ tr = (0, _utils4.selectNode)(tr, mappedTo, node.type.name);
168
193
  tr.setMeta(_main.key, {
169
194
  nodeMoved: true
170
195
  });
@@ -4,18 +4,51 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.showDragHandleAtSelection = void 0;
7
+ var _utils = require("@atlaskit/editor-tables/utils");
7
8
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
8
- var showDragHandleAtSelection = exports.showDragHandleAtSelection = function showDragHandleAtSelection(api) {
9
+ var _main = require("../pm-plugins/main");
10
+ var _utils2 = require("../utils");
11
+ var showDragHandleAtSelection = exports.showDragHandleAtSelection = function showDragHandleAtSelection(api, shouldFocusParentNode) {
9
12
  return function (state, _, view) {
10
- var rootPos = state.selection.$from.before(1);
13
+ var $from = state.selection.$from;
14
+ var shouldFocusParentNode;
15
+ if ($from.depth > 1 && (0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y')) {
16
+ var _activeNode$handleOpt, _view$domAtPos;
17
+ var _ref = _main.key.getState(state) || {},
18
+ activeNode = _ref.activeNode;
19
+
20
+ // if the node is already focused, pressing the keymap second times should focus the parent node
21
+ shouldFocusParentNode = activeNode && ((_activeNode$handleOpt = activeNode.handleOptions) === null || _activeNode$handleOpt === void 0 ? void 0 : _activeNode$handleOpt.isFocused);
22
+ var parentPos = (0, _utils.isInTable)(state) ? $from.before(1) : shouldFocusParentNode ? $from.before(1) : (0, _utils2.getNestedNodePosition)(state) + 1;
23
+ var parentElement = view === null || view === void 0 || (_view$domAtPos = view.domAtPos(parentPos, 0)) === null || _view$domAtPos === void 0 ? void 0 : _view$domAtPos.node;
24
+ if (parentElement) {
25
+ var anchorName = parentElement.getAttribute('data-drag-handler-anchor-name');
26
+ var nodeType = parentElement.getAttribute('data-drag-handler-node-type');
27
+ if (!anchorName || !nodeType) {
28
+ // for nodes like panel and mediaSingle, the drag handle decoration is not applied to the dom node at the node position but to the parent node
29
+ var closestParentElement = parentElement.closest('[data-drag-handler-anchor-name]');
30
+ if (closestParentElement) {
31
+ anchorName = closestParentElement.getAttribute('data-drag-handler-anchor-name');
32
+ nodeType = closestParentElement.getAttribute('data-drag-handler-node-type');
33
+ }
34
+ }
35
+ if (api && anchorName && nodeType) {
36
+ api.core.actions.execute(api.blockControls.commands.showDragHandleAt(parentPos - 1, anchorName, nodeType, {
37
+ isFocused: true
38
+ }));
39
+ return true;
40
+ }
41
+ }
42
+ }
43
+ var rootPos = $from.before(1);
11
44
  var dom = view === null || view === void 0 ? void 0 : view.domAtPos(rootPos, 0);
12
45
  var nodeElement = dom === null || dom === void 0 ? void 0 : dom.node.childNodes[dom === null || dom === void 0 ? void 0 : dom.offset];
13
46
  var rootNode = nodeElement && !nodeElement.hasAttribute('data-drag-handler-anchor-name') && (0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_24321') ? nodeElement.querySelector('[data-drag-handler-anchor-name]') : nodeElement;
14
47
  if (rootNode) {
15
- var anchorName = rootNode.getAttribute('data-drag-handler-anchor-name');
16
- var nodeType = rootNode.getAttribute('data-drag-handler-node-type');
17
- if (api && anchorName && nodeType) {
18
- api.core.actions.execute(api.blockControls.commands.showDragHandleAt(rootPos, anchorName, nodeType, {
48
+ var _anchorName = rootNode.getAttribute('data-drag-handler-anchor-name');
49
+ var _nodeType = rootNode.getAttribute('data-drag-handler-node-type');
50
+ if (api && _anchorName && _nodeType) {
51
+ api.core.actions.execute(api.blockControls.commands.showDragHandleAt(rootPos, _anchorName, _nodeType, {
19
52
  isFocused: true
20
53
  }));
21
54
  return true;
@@ -7,5 +7,7 @@ exports.DIRECTION = void 0;
7
7
  var DIRECTION = exports.DIRECTION = /*#__PURE__*/function (DIRECTION) {
8
8
  DIRECTION["UP"] = "up";
9
9
  DIRECTION["DOWN"] = "down";
10
+ DIRECTION["LEFT"] = "left";
11
+ DIRECTION["RIGHT"] = "right";
10
12
  return DIRECTION;
11
13
  }({});
@@ -16,7 +16,7 @@ var isEmptyNestedParagraphOrHeading = function isEmptyNestedParagraphOrHeading(t
16
16
  var isDocFirstChildEmptyLine = function isDocFirstChildEmptyLine(elem) {
17
17
  var _elem$firstElementChi;
18
18
  var parentElement = elem.parentElement;
19
- return (parentElement === null || parentElement === void 0 ? void 0 : parentElement.firstElementChild) === elem && ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(elem.nodeName) && elem.childNodes.length === 1 && ((_elem$firstElementChi = elem.firstElementChild) === null || _elem$firstElementChi === void 0 ? void 0 : _elem$firstElementChi.classList.contains('ProseMirror-trailingBreak'));
19
+ return (parentElement === null || parentElement === void 0 ? void 0 : parentElement.classList.contains('ProseMirror')) && (parentElement === null || parentElement === void 0 ? void 0 : parentElement.firstElementChild) === elem && ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(elem.nodeName) && elem.childNodes.length === 1 && ((_elem$firstElementChi = elem.firstElementChild) === null || _elem$firstElementChi === void 0 ? void 0 : _elem$firstElementChi.classList.contains('ProseMirror-trailingBreak'));
20
20
  };
21
21
  var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, event, api) {
22
22
  var _api$blockControls;
@@ -20,6 +20,8 @@ function keymapList(api, formatMessage) {
20
20
  }, keymapList);
21
21
  (0, _keymaps.bindKeymapWithCommand)(_keymaps.dragToMoveUp.common, (0, _moveNode.moveNodeViaShortcut)(api, _consts.DIRECTION.UP, formatMessage), keymapList);
22
22
  (0, _keymaps.bindKeymapWithCommand)(_keymaps.dragToMoveDown.common, (0, _moveNode.moveNodeViaShortcut)(api, _consts.DIRECTION.DOWN, formatMessage), keymapList);
23
+ (0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y') && (0, _keymaps.bindKeymapWithCommand)(_keymaps.dragToMoveLeft.common, (0, _moveNode.moveNodeViaShortcut)(api, _consts.DIRECTION.LEFT, formatMessage), keymapList);
24
+ (0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y') && (0, _keymaps.bindKeymapWithCommand)(_keymaps.dragToMoveRight.common, (0, _moveNode.moveNodeViaShortcut)(api, _consts.DIRECTION.RIGHT, formatMessage), keymapList);
23
25
  }
24
26
  return keymapList;
25
27
  }
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.DragHandle = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
8
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
10
  var _react = require("react");
10
11
  var _react2 = require("@emotion/react");
@@ -368,7 +369,26 @@ var DragHandleInternal = function DragHandleInternal(_ref) {
368
369
  keymap: _keymaps.dragToMoveDown
369
370
  }] : [{
370
371
  description: formatMessage(_messages.blockControlsMessages.dragToMove)
372
+ }, {
373
+ description: formatMessage(_messages.blockControlsMessages.moveUp),
374
+ keymap: _keymaps.dragToMoveUp
375
+ }, {
376
+ description: formatMessage(_messages.blockControlsMessages.moveDown),
377
+ keymap: _keymaps.dragToMoveDown
371
378
  }];
379
+ var isParentNodeOfTypeLayout;
380
+ if (!isTopLevelNode && handleOptions !== null && handleOptions !== void 0 && handleOptions.isFocused && (0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_a11y')) {
381
+ isParentNodeOfTypeLayout = nodeType === 'layoutSection' || view.state.doc.resolve((0, _utils.getNestedNodePosition)(view.state)).node().type.name === 'layoutColumn';
382
+ if (isParentNodeOfTypeLayout) {
383
+ helpDescriptors = [].concat((0, _toConsumableArray2.default)(helpDescriptors), [{
384
+ description: formatMessage(_messages.blockControlsMessages.moveLeft),
385
+ keymap: _keymaps.dragToMoveLeft
386
+ }, {
387
+ description: formatMessage(_messages.blockControlsMessages.moveRight),
388
+ keymap: _keymaps.dragToMoveRight
389
+ }]);
390
+ }
391
+ }
372
392
  var message = helpDescriptors.map(function (descriptor) {
373
393
  return descriptor.keymap ? [descriptor.description, (0, _keymaps.getAriaKeyshortcuts)(descriptor.keymap)] : [descriptor.description];
374
394
  }).join('. ');
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getNestedNodePosition = void 0;
7
+ var _state = require("@atlaskit/editor-prosemirror/state");
8
+ var _utils = require("@atlaskit/editor-prosemirror/utils");
9
+ var getNestedNodePosition = exports.getNestedNodePosition = function getNestedNodePosition(state) {
10
+ var selection = state.selection;
11
+ var nestedNodePos = selection.$from.before(1);
12
+ if (selection instanceof _state.TextSelection) {
13
+ nestedNodePos = selection.$from.before();
14
+ var $pos = state.doc.resolve(nestedNodePos);
15
+ if ($pos.depth < 1) {
16
+ return nestedNodePos;
17
+ }
18
+ var parentNodeOfSpecificTypes = (0, _utils.findParentNodeOfType)([state.schema.nodes.bulletList, state.schema.nodes.orderedList, state.schema.nodes.blockquote, state.schema.nodes.taskList])(state.selection);
19
+ if (parentNodeOfSpecificTypes) {
20
+ var parentNodeType = parentNodeOfSpecificTypes.node.type.name;
21
+ nestedNodePos = ['bulletList', 'orderedList'].includes(parentNodeType) ? $pos.before($pos.depth - 1) : ['blockquote', 'taskList'].includes(parentNodeType) ? $pos.before() : nestedNodePos;
22
+ }
23
+ } else {
24
+ nestedNodePos = selection.$from.pos;
25
+ }
26
+ return nestedNodePos;
27
+ };
@@ -3,6 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ Object.defineProperty(exports, "getNestedNodePosition", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _getNestedNodePosition.getNestedNodePosition;
10
+ }
11
+ });
6
12
  Object.defineProperty(exports, "getSelection", {
7
13
  enumerable: true,
8
14
  get: function get() {
@@ -15,4 +21,5 @@ Object.defineProperty(exports, "selectNode", {
15
21
  return _getSelection.selectNode;
16
22
  }
17
23
  });
18
- var _getSelection = require("./getSelection");
24
+ var _getSelection = require("./getSelection");
25
+ var _getNestedNodePosition = require("./getNestedNodePosition");
@@ -3,12 +3,13 @@ import { blockControlsMessages } from '@atlaskit/editor-common/messages';
3
3
  import { GapCursorSelection } from '@atlaskit/editor-common/selection';
4
4
  import { transformSliceNestedExpandToExpand } from '@atlaskit/editor-common/transforms';
5
5
  import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
6
+ import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
6
7
  import { findTable, isInTable, isTableSelected } from '@atlaskit/editor-tables/utils';
7
8
  import { fg } from '@atlaskit/platform-feature-flags';
8
9
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
9
10
  import { DIRECTION } from '../consts';
10
11
  import { key } from '../pm-plugins/main';
11
- import { selectNode } from '../utils';
12
+ import { getNestedNodePosition, selectNode } from '../utils';
12
13
  import { canMoveNodeToIndex, isInsideTable, transformSliceExpandToNestedExpand } from '../utils/validation';
13
14
 
14
15
  /**
@@ -38,7 +39,7 @@ function transformSourceSlice(nodeCopy, destType) {
38
39
  *
39
40
  * @returns the start position of a node if the node can be moved, otherwise -1
40
41
  */
41
- const getCurrentNodePos = state => {
42
+ const getCurrentNodePos = (state, isParentNodeOfTypeLayout) => {
42
43
  var _activeNode$handleOpt;
43
44
  const {
44
45
  selection
@@ -63,21 +64,42 @@ const getCurrentNodePos = state => {
63
64
  // 2. caret cursor is inside the node
64
65
  // 3. the start of the selection is inside the node
65
66
  currentNodePos = selection.$from.before(1);
67
+ if (selection.$from.depth > 0 && fg('platform_editor_element_dnd_nested_a11y')) {
68
+ currentNodePos = getNestedNodePosition(state);
69
+ }
66
70
  }
67
71
  return currentNodePos;
68
72
  };
69
73
  export const moveNodeViaShortcut = (api, direction, formatMessage) => {
70
74
  return state => {
71
- const currentNodePos = getCurrentNodePos(state);
75
+ let isParentNodeOfTypeLayout;
76
+ if (fg('platform_editor_element_dnd_nested_a11y')) {
77
+ isParentNodeOfTypeLayout = !!findParentNodeOfType([state.schema.nodes.layoutSection])(state.selection);
78
+ }
79
+ const currentNodePos = getCurrentNodePos(state, isParentNodeOfTypeLayout);
72
80
  if (currentNodePos > -1) {
73
81
  var _state$doc$nodeAt;
74
82
  const $pos = state.doc.resolve(currentNodePos);
75
83
  let moveToPos = -1;
76
- if (direction === DIRECTION.UP) {
77
- const nodeBefore = $pos.nodeBefore;
78
- if (nodeBefore) {
79
- moveToPos = currentNodePos - nodeBefore.nodeSize;
84
+ const nodeIndex = $pos.index();
85
+ if (direction === DIRECTION.LEFT && fg('platform_editor_element_dnd_nested_a11y')) {
86
+ if ($pos.depth < 2 || !isParentNodeOfTypeLayout) {
87
+ return false;
80
88
  }
89
+
90
+ // get the previous layoutSection node
91
+ const index = $pos.index($pos.depth - 1);
92
+ const grandParent = $pos.node($pos.depth - 1);
93
+ const previousNode = grandParent ? grandParent.maybeChild(index - 1) : null;
94
+ moveToPos = $pos.start() - ((previousNode === null || previousNode === void 0 ? void 0 : previousNode.nodeSize) || 1);
95
+ } else if (direction === DIRECTION.RIGHT && fg('platform_editor_element_dnd_nested_a11y')) {
96
+ if ($pos.depth < 2 || !isParentNodeOfTypeLayout) {
97
+ return false;
98
+ }
99
+ moveToPos = $pos.after($pos.depth) + 1;
100
+ } else if (direction === DIRECTION.UP) {
101
+ const nodeBefore = $pos.depth > 1 && nodeIndex === 0 && fg('platform_editor_element_dnd_nested_a11y') ? $pos.node($pos.depth) : $pos.nodeBefore;
102
+ moveToPos = $pos.depth > 1 && nodeIndex === 0 && fg('platform_editor_element_dnd_nested_a11y') ? $pos.before($pos.depth) - 1 : nodeBefore ? currentNodePos - nodeBefore.nodeSize : moveToPos;
81
103
  } else {
82
104
  const endOfDoc = $pos.end();
83
105
  const nodeAfterPos = $pos.posAtIndex($pos.index() + 1);
@@ -88,7 +110,10 @@ export const moveNodeViaShortcut = (api, direction, formatMessage) => {
88
110
  }
89
111
  }
90
112
  const nodeType = (_state$doc$nodeAt = state.doc.nodeAt(currentNodePos)) === null || _state$doc$nodeAt === void 0 ? void 0 : _state$doc$nodeAt.type.name;
91
- if (moveToPos > -1) {
113
+
114
+ // only move the node if the destination is at the same depth, not support moving a nested node to a parent node
115
+ const shouldMoveNode = fg('platform_editor_element_dnd_nested_a11y') ? moveToPos > -1 && $pos.depth === state.doc.resolve(moveToPos).depth : moveToPos > -1;
116
+ if (shouldMoveNode) {
92
117
  var _api$core;
93
118
  api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
94
119
  tr
@@ -1,6 +1,42 @@
1
+ import { isInTable } from '@atlaskit/editor-tables/utils';
1
2
  import { fg } from '@atlaskit/platform-feature-flags';
2
- export const showDragHandleAtSelection = api => (state, _, view) => {
3
- const rootPos = state.selection.$from.before(1);
3
+ import { key } from '../pm-plugins/main';
4
+ import { getNestedNodePosition } from '../utils';
5
+ export const showDragHandleAtSelection = (api, shouldFocusParentNode) => (state, _, view) => {
6
+ const {
7
+ $from
8
+ } = state.selection;
9
+ let shouldFocusParentNode;
10
+ if ($from.depth > 1 && fg('platform_editor_element_dnd_nested_a11y')) {
11
+ var _activeNode$handleOpt, _view$domAtPos;
12
+ const {
13
+ activeNode
14
+ } = key.getState(state) || {};
15
+
16
+ // if the node is already focused, pressing the keymap second times should focus the parent node
17
+ shouldFocusParentNode = activeNode && ((_activeNode$handleOpt = activeNode.handleOptions) === null || _activeNode$handleOpt === void 0 ? void 0 : _activeNode$handleOpt.isFocused);
18
+ const parentPos = isInTable(state) ? $from.before(1) : shouldFocusParentNode ? $from.before(1) : getNestedNodePosition(state) + 1;
19
+ const parentElement = view === null || view === void 0 ? void 0 : (_view$domAtPos = view.domAtPos(parentPos, 0)) === null || _view$domAtPos === void 0 ? void 0 : _view$domAtPos.node;
20
+ if (parentElement) {
21
+ let anchorName = parentElement.getAttribute('data-drag-handler-anchor-name');
22
+ let nodeType = parentElement.getAttribute('data-drag-handler-node-type');
23
+ if (!anchorName || !nodeType) {
24
+ // for nodes like panel and mediaSingle, the drag handle decoration is not applied to the dom node at the node position but to the parent node
25
+ const closestParentElement = parentElement.closest('[data-drag-handler-anchor-name]');
26
+ if (closestParentElement) {
27
+ anchorName = closestParentElement.getAttribute('data-drag-handler-anchor-name');
28
+ nodeType = closestParentElement.getAttribute('data-drag-handler-node-type');
29
+ }
30
+ }
31
+ if (api && anchorName && nodeType) {
32
+ api.core.actions.execute(api.blockControls.commands.showDragHandleAt(parentPos - 1, anchorName, nodeType, {
33
+ isFocused: true
34
+ }));
35
+ return true;
36
+ }
37
+ }
38
+ }
39
+ const rootPos = $from.before(1);
4
40
  const dom = view === null || view === void 0 ? void 0 : view.domAtPos(rootPos, 0);
5
41
  const nodeElement = dom === null || dom === void 0 ? void 0 : dom.node.childNodes[dom === null || dom === void 0 ? void 0 : dom.offset];
6
42
  const rootNode = nodeElement && !nodeElement.hasAttribute('data-drag-handler-anchor-name') && fg('platform_editor_element_drag_and_drop_ed_24321') ? nodeElement.querySelector('[data-drag-handler-anchor-name]') : nodeElement;
@@ -1,5 +1,7 @@
1
1
  export let DIRECTION = /*#__PURE__*/function (DIRECTION) {
2
2
  DIRECTION["UP"] = "up";
3
3
  DIRECTION["DOWN"] = "down";
4
+ DIRECTION["LEFT"] = "left";
5
+ DIRECTION["RIGHT"] = "right";
4
6
  return DIRECTION;
5
7
  }({});
@@ -10,7 +10,7 @@ const isEmptyNestedParagraphOrHeading = target => {
10
10
  const isDocFirstChildEmptyLine = elem => {
11
11
  var _elem$firstElementChi;
12
12
  const parentElement = elem.parentElement;
13
- return (parentElement === null || parentElement === void 0 ? void 0 : parentElement.firstElementChild) === elem && ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(elem.nodeName) && elem.childNodes.length === 1 && ((_elem$firstElementChi = elem.firstElementChild) === null || _elem$firstElementChi === void 0 ? void 0 : _elem$firstElementChi.classList.contains('ProseMirror-trailingBreak'));
13
+ return (parentElement === null || parentElement === void 0 ? void 0 : parentElement.classList.contains('ProseMirror')) && (parentElement === null || parentElement === void 0 ? void 0 : parentElement.firstElementChild) === elem && ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(elem.nodeName) && elem.childNodes.length === 1 && ((_elem$firstElementChi = elem.firstElementChild) === null || _elem$firstElementChi === void 0 ? void 0 : _elem$firstElementChi.classList.contains('ProseMirror-trailingBreak'));
14
14
  };
15
15
  export const handleMouseOver = (view, event, api) => {
16
16
  var _api$blockControls;
@@ -1,4 +1,4 @@
1
- import { bindKeymapWithCommand, dragToMoveDown, dragToMoveUp, showElementDragHandle } from '@atlaskit/editor-common/keymaps';
1
+ import { bindKeymapWithCommand, dragToMoveDown, dragToMoveLeft, dragToMoveRight, dragToMoveUp, showElementDragHandle } from '@atlaskit/editor-common/keymaps';
2
2
  import { keydownHandler } from '@atlaskit/editor-prosemirror/keymap';
3
3
  import { fg } from '@atlaskit/platform-feature-flags';
4
4
  import { moveNodeViaShortcut } from '../commands/move-node';
@@ -14,6 +14,8 @@ function keymapList(api, formatMessage) {
14
14
  }, keymapList);
15
15
  bindKeymapWithCommand(dragToMoveUp.common, moveNodeViaShortcut(api, DIRECTION.UP, formatMessage), keymapList);
16
16
  bindKeymapWithCommand(dragToMoveDown.common, moveNodeViaShortcut(api, DIRECTION.DOWN, formatMessage), keymapList);
17
+ fg('platform_editor_element_dnd_nested_a11y') && bindKeymapWithCommand(dragToMoveLeft.common, moveNodeViaShortcut(api, DIRECTION.LEFT, formatMessage), keymapList);
18
+ fg('platform_editor_element_dnd_nested_a11y') && bindKeymapWithCommand(dragToMoveRight.common, moveNodeViaShortcut(api, DIRECTION.RIGHT, formatMessage), keymapList);
17
19
  }
18
20
  return keymapList;
19
21
  }
@@ -9,7 +9,7 @@ import { bind } from 'bind-event-listener';
9
9
  import { injectIntl } from 'react-intl-next';
10
10
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
11
11
  import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
12
- import { dragToMoveDown, dragToMoveUp, getAriaKeyshortcuts, TooltipContentWithMultipleShortcuts } from '@atlaskit/editor-common/keymaps';
12
+ import { dragToMoveDown, dragToMoveLeft, dragToMoveRight, dragToMoveUp, getAriaKeyshortcuts, TooltipContentWithMultipleShortcuts } from '@atlaskit/editor-common/keymaps';
13
13
  import { blockControlsMessages } from '@atlaskit/editor-common/messages';
14
14
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
15
15
  import DragHandlerIcon from '@atlaskit/icon/glyph/drag-handler';
@@ -19,7 +19,7 @@ import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/el
19
19
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
20
20
  import Tooltip from '@atlaskit/tooltip';
21
21
  import { key } from '../pm-plugins/main';
22
- import { selectNode } from '../utils';
22
+ import { getNestedNodePosition, selectNode } from '../utils';
23
23
  import { getLeftPosition, getTopPosition } from '../utils/drag-handle-positions';
24
24
  import { DRAG_HANDLE_BORDER_RADIUS, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_WIDTH, DRAG_HANDLE_ZINDEX, dragHandleGap, topPositionAdjustment } from './consts';
25
25
  import { dragPreview } from './drag-preview';
@@ -342,7 +342,7 @@ const DragHandleInternal = ({
342
342
  };
343
343
  }
344
344
  }, [buttonRef, handleOptions === null || handleOptions === void 0 ? void 0 : handleOptions.isFocused, view]);
345
- const helpDescriptors = isTopLevelNode ? [{
345
+ let helpDescriptors = isTopLevelNode ? [{
346
346
  description: formatMessage(blockControlsMessages.dragToMove)
347
347
  }, {
348
348
  description: formatMessage(blockControlsMessages.moveUp),
@@ -352,7 +352,26 @@ const DragHandleInternal = ({
352
352
  keymap: dragToMoveDown
353
353
  }] : [{
354
354
  description: formatMessage(blockControlsMessages.dragToMove)
355
+ }, {
356
+ description: formatMessage(blockControlsMessages.moveUp),
357
+ keymap: dragToMoveUp
358
+ }, {
359
+ description: formatMessage(blockControlsMessages.moveDown),
360
+ keymap: dragToMoveDown
355
361
  }];
362
+ let isParentNodeOfTypeLayout;
363
+ if (!isTopLevelNode && handleOptions !== null && handleOptions !== void 0 && handleOptions.isFocused && fg('platform_editor_element_dnd_nested_a11y')) {
364
+ isParentNodeOfTypeLayout = nodeType === 'layoutSection' || view.state.doc.resolve(getNestedNodePosition(view.state)).node().type.name === 'layoutColumn';
365
+ if (isParentNodeOfTypeLayout) {
366
+ helpDescriptors = [...helpDescriptors, {
367
+ description: formatMessage(blockControlsMessages.moveLeft),
368
+ keymap: dragToMoveLeft
369
+ }, {
370
+ description: formatMessage(blockControlsMessages.moveRight),
371
+ keymap: dragToMoveRight
372
+ }];
373
+ }
374
+ }
356
375
  const message = helpDescriptors.map(descriptor => {
357
376
  return descriptor.keymap ? [descriptor.description, getAriaKeyshortcuts(descriptor.keymap)] : [descriptor.description];
358
377
  }).join('. ');
@@ -0,0 +1,23 @@
1
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
2
+ import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
3
+ export const getNestedNodePosition = state => {
4
+ const {
5
+ selection
6
+ } = state;
7
+ let nestedNodePos = selection.$from.before(1);
8
+ if (selection instanceof TextSelection) {
9
+ nestedNodePos = selection.$from.before();
10
+ const $pos = state.doc.resolve(nestedNodePos);
11
+ if ($pos.depth < 1) {
12
+ return nestedNodePos;
13
+ }
14
+ const parentNodeOfSpecificTypes = findParentNodeOfType([state.schema.nodes.bulletList, state.schema.nodes.orderedList, state.schema.nodes.blockquote, state.schema.nodes.taskList])(state.selection);
15
+ if (parentNodeOfSpecificTypes) {
16
+ const parentNodeType = parentNodeOfSpecificTypes.node.type.name;
17
+ nestedNodePos = ['bulletList', 'orderedList'].includes(parentNodeType) ? $pos.before($pos.depth - 1) : ['blockquote', 'taskList'].includes(parentNodeType) ? $pos.before() : nestedNodePos;
18
+ }
19
+ } else {
20
+ nestedNodePos = selection.$from.pos;
21
+ }
22
+ return nestedNodePos;
23
+ };
@@ -1 +1,2 @@
1
- export { getSelection, selectNode } from './getSelection';
1
+ export { getSelection, selectNode } from './getSelection';
2
+ export { getNestedNodePosition } from './getNestedNodePosition';
@@ -6,12 +6,13 @@ import { blockControlsMessages } from '@atlaskit/editor-common/messages';
6
6
  import { GapCursorSelection } from '@atlaskit/editor-common/selection';
7
7
  import { transformSliceNestedExpandToExpand } from '@atlaskit/editor-common/transforms';
8
8
  import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
9
+ import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
9
10
  import { findTable, isInTable, isTableSelected } from '@atlaskit/editor-tables/utils';
10
11
  import { fg } from '@atlaskit/platform-feature-flags';
11
12
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
12
13
  import { DIRECTION } from '../consts';
13
14
  import { key } from '../pm-plugins/main';
14
- import { selectNode } from '../utils';
15
+ import { getNestedNodePosition, selectNode } from '../utils';
15
16
  import { canMoveNodeToIndex, isInsideTable, transformSliceExpandToNestedExpand } from '../utils/validation';
16
17
 
17
18
  /**
@@ -40,7 +41,7 @@ function transformSourceSlice(nodeCopy, destType) {
40
41
  *
41
42
  * @returns the start position of a node if the node can be moved, otherwise -1
42
43
  */
43
- var getCurrentNodePos = function getCurrentNodePos(state) {
44
+ var getCurrentNodePos = function getCurrentNodePos(state, isParentNodeOfTypeLayout) {
44
45
  var _activeNode$handleOpt;
45
46
  var selection = state.selection;
46
47
  var _ref = key.getState(state) || {},
@@ -62,21 +63,42 @@ var getCurrentNodePos = function getCurrentNodePos(state) {
62
63
  // 2. caret cursor is inside the node
63
64
  // 3. the start of the selection is inside the node
64
65
  currentNodePos = selection.$from.before(1);
66
+ if (selection.$from.depth > 0 && fg('platform_editor_element_dnd_nested_a11y')) {
67
+ currentNodePos = getNestedNodePosition(state);
68
+ }
65
69
  }
66
70
  return currentNodePos;
67
71
  };
68
72
  export var moveNodeViaShortcut = function moveNodeViaShortcut(api, direction, formatMessage) {
69
73
  return function (state) {
70
- var currentNodePos = getCurrentNodePos(state);
74
+ var isParentNodeOfTypeLayout;
75
+ if (fg('platform_editor_element_dnd_nested_a11y')) {
76
+ isParentNodeOfTypeLayout = !!findParentNodeOfType([state.schema.nodes.layoutSection])(state.selection);
77
+ }
78
+ var currentNodePos = getCurrentNodePos(state, isParentNodeOfTypeLayout);
71
79
  if (currentNodePos > -1) {
72
80
  var _state$doc$nodeAt;
73
81
  var $pos = state.doc.resolve(currentNodePos);
74
82
  var moveToPos = -1;
75
- if (direction === DIRECTION.UP) {
76
- var nodeBefore = $pos.nodeBefore;
77
- if (nodeBefore) {
78
- moveToPos = currentNodePos - nodeBefore.nodeSize;
83
+ var nodeIndex = $pos.index();
84
+ if (direction === DIRECTION.LEFT && fg('platform_editor_element_dnd_nested_a11y')) {
85
+ if ($pos.depth < 2 || !isParentNodeOfTypeLayout) {
86
+ return false;
79
87
  }
88
+
89
+ // get the previous layoutSection node
90
+ var index = $pos.index($pos.depth - 1);
91
+ var grandParent = $pos.node($pos.depth - 1);
92
+ var previousNode = grandParent ? grandParent.maybeChild(index - 1) : null;
93
+ moveToPos = $pos.start() - ((previousNode === null || previousNode === void 0 ? void 0 : previousNode.nodeSize) || 1);
94
+ } else if (direction === DIRECTION.RIGHT && fg('platform_editor_element_dnd_nested_a11y')) {
95
+ if ($pos.depth < 2 || !isParentNodeOfTypeLayout) {
96
+ return false;
97
+ }
98
+ moveToPos = $pos.after($pos.depth) + 1;
99
+ } else if (direction === DIRECTION.UP) {
100
+ var nodeBefore = $pos.depth > 1 && nodeIndex === 0 && fg('platform_editor_element_dnd_nested_a11y') ? $pos.node($pos.depth) : $pos.nodeBefore;
101
+ moveToPos = $pos.depth > 1 && nodeIndex === 0 && fg('platform_editor_element_dnd_nested_a11y') ? $pos.before($pos.depth) - 1 : nodeBefore ? currentNodePos - nodeBefore.nodeSize : moveToPos;
80
102
  } else {
81
103
  var endOfDoc = $pos.end();
82
104
  var nodeAfterPos = $pos.posAtIndex($pos.index() + 1);
@@ -87,7 +109,10 @@ export var moveNodeViaShortcut = function moveNodeViaShortcut(api, direction, fo
87
109
  }
88
110
  }
89
111
  var nodeType = (_state$doc$nodeAt = state.doc.nodeAt(currentNodePos)) === null || _state$doc$nodeAt === void 0 ? void 0 : _state$doc$nodeAt.type.name;
90
- if (moveToPos > -1) {
112
+
113
+ // only move the node if the destination is at the same depth, not support moving a nested node to a parent node
114
+ var shouldMoveNode = fg('platform_editor_element_dnd_nested_a11y') ? moveToPos > -1 && $pos.depth === state.doc.resolve(moveToPos).depth : moveToPos > -1;
115
+ if (shouldMoveNode) {
91
116
  var _api$core;
92
117
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref2) {
93
118
  var tr = _ref2.tr;
@@ -1,15 +1,48 @@
1
+ import { isInTable } from '@atlaskit/editor-tables/utils';
1
2
  import { fg } from '@atlaskit/platform-feature-flags';
2
- export var showDragHandleAtSelection = function showDragHandleAtSelection(api) {
3
+ import { key } from '../pm-plugins/main';
4
+ import { getNestedNodePosition } from '../utils';
5
+ export var showDragHandleAtSelection = function showDragHandleAtSelection(api, shouldFocusParentNode) {
3
6
  return function (state, _, view) {
4
- var rootPos = state.selection.$from.before(1);
7
+ var $from = state.selection.$from;
8
+ var shouldFocusParentNode;
9
+ if ($from.depth > 1 && fg('platform_editor_element_dnd_nested_a11y')) {
10
+ var _activeNode$handleOpt, _view$domAtPos;
11
+ var _ref = key.getState(state) || {},
12
+ activeNode = _ref.activeNode;
13
+
14
+ // if the node is already focused, pressing the keymap second times should focus the parent node
15
+ shouldFocusParentNode = activeNode && ((_activeNode$handleOpt = activeNode.handleOptions) === null || _activeNode$handleOpt === void 0 ? void 0 : _activeNode$handleOpt.isFocused);
16
+ var parentPos = isInTable(state) ? $from.before(1) : shouldFocusParentNode ? $from.before(1) : getNestedNodePosition(state) + 1;
17
+ var parentElement = view === null || view === void 0 || (_view$domAtPos = view.domAtPos(parentPos, 0)) === null || _view$domAtPos === void 0 ? void 0 : _view$domAtPos.node;
18
+ if (parentElement) {
19
+ var anchorName = parentElement.getAttribute('data-drag-handler-anchor-name');
20
+ var nodeType = parentElement.getAttribute('data-drag-handler-node-type');
21
+ if (!anchorName || !nodeType) {
22
+ // for nodes like panel and mediaSingle, the drag handle decoration is not applied to the dom node at the node position but to the parent node
23
+ var closestParentElement = parentElement.closest('[data-drag-handler-anchor-name]');
24
+ if (closestParentElement) {
25
+ anchorName = closestParentElement.getAttribute('data-drag-handler-anchor-name');
26
+ nodeType = closestParentElement.getAttribute('data-drag-handler-node-type');
27
+ }
28
+ }
29
+ if (api && anchorName && nodeType) {
30
+ api.core.actions.execute(api.blockControls.commands.showDragHandleAt(parentPos - 1, anchorName, nodeType, {
31
+ isFocused: true
32
+ }));
33
+ return true;
34
+ }
35
+ }
36
+ }
37
+ var rootPos = $from.before(1);
5
38
  var dom = view === null || view === void 0 ? void 0 : view.domAtPos(rootPos, 0);
6
39
  var nodeElement = dom === null || dom === void 0 ? void 0 : dom.node.childNodes[dom === null || dom === void 0 ? void 0 : dom.offset];
7
40
  var rootNode = nodeElement && !nodeElement.hasAttribute('data-drag-handler-anchor-name') && fg('platform_editor_element_drag_and_drop_ed_24321') ? nodeElement.querySelector('[data-drag-handler-anchor-name]') : nodeElement;
8
41
  if (rootNode) {
9
- var anchorName = rootNode.getAttribute('data-drag-handler-anchor-name');
10
- var nodeType = rootNode.getAttribute('data-drag-handler-node-type');
11
- if (api && anchorName && nodeType) {
12
- api.core.actions.execute(api.blockControls.commands.showDragHandleAt(rootPos, anchorName, nodeType, {
42
+ var _anchorName = rootNode.getAttribute('data-drag-handler-anchor-name');
43
+ var _nodeType = rootNode.getAttribute('data-drag-handler-node-type');
44
+ if (api && _anchorName && _nodeType) {
45
+ api.core.actions.execute(api.blockControls.commands.showDragHandleAt(rootPos, _anchorName, _nodeType, {
13
46
  isFocused: true
14
47
  }));
15
48
  return true;
@@ -1,5 +1,7 @@
1
1
  export var DIRECTION = /*#__PURE__*/function (DIRECTION) {
2
2
  DIRECTION["UP"] = "up";
3
3
  DIRECTION["DOWN"] = "down";
4
+ DIRECTION["LEFT"] = "left";
5
+ DIRECTION["RIGHT"] = "right";
4
6
  return DIRECTION;
5
7
  }({});
@@ -10,7 +10,7 @@ var isEmptyNestedParagraphOrHeading = function isEmptyNestedParagraphOrHeading(t
10
10
  var isDocFirstChildEmptyLine = function isDocFirstChildEmptyLine(elem) {
11
11
  var _elem$firstElementChi;
12
12
  var parentElement = elem.parentElement;
13
- return (parentElement === null || parentElement === void 0 ? void 0 : parentElement.firstElementChild) === elem && ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(elem.nodeName) && elem.childNodes.length === 1 && ((_elem$firstElementChi = elem.firstElementChild) === null || _elem$firstElementChi === void 0 ? void 0 : _elem$firstElementChi.classList.contains('ProseMirror-trailingBreak'));
13
+ return (parentElement === null || parentElement === void 0 ? void 0 : parentElement.classList.contains('ProseMirror')) && (parentElement === null || parentElement === void 0 ? void 0 : parentElement.firstElementChild) === elem && ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(elem.nodeName) && elem.childNodes.length === 1 && ((_elem$firstElementChi = elem.firstElementChild) === null || _elem$firstElementChi === void 0 ? void 0 : _elem$firstElementChi.classList.contains('ProseMirror-trailingBreak'));
14
14
  };
15
15
  export var handleMouseOver = function handleMouseOver(view, event, api) {
16
16
  var _api$blockControls;
@@ -1,4 +1,4 @@
1
- import { bindKeymapWithCommand, dragToMoveDown, dragToMoveUp, showElementDragHandle } from '@atlaskit/editor-common/keymaps';
1
+ import { bindKeymapWithCommand, dragToMoveDown, dragToMoveLeft, dragToMoveRight, dragToMoveUp, showElementDragHandle } from '@atlaskit/editor-common/keymaps';
2
2
  import { keydownHandler } from '@atlaskit/editor-prosemirror/keymap';
3
3
  import { fg } from '@atlaskit/platform-feature-flags';
4
4
  import { moveNodeViaShortcut } from '../commands/move-node';
@@ -14,6 +14,8 @@ function keymapList(api, formatMessage) {
14
14
  }, keymapList);
15
15
  bindKeymapWithCommand(dragToMoveUp.common, moveNodeViaShortcut(api, DIRECTION.UP, formatMessage), keymapList);
16
16
  bindKeymapWithCommand(dragToMoveDown.common, moveNodeViaShortcut(api, DIRECTION.DOWN, formatMessage), keymapList);
17
+ fg('platform_editor_element_dnd_nested_a11y') && bindKeymapWithCommand(dragToMoveLeft.common, moveNodeViaShortcut(api, DIRECTION.LEFT, formatMessage), keymapList);
18
+ fg('platform_editor_element_dnd_nested_a11y') && bindKeymapWithCommand(dragToMoveRight.common, moveNodeViaShortcut(api, DIRECTION.RIGHT, formatMessage), keymapList);
17
19
  }
18
20
  return keymapList;
19
21
  }
@@ -1,3 +1,4 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
3
  /**
3
4
  * @jsxRuntime classic
@@ -10,7 +11,7 @@ import { bind } from 'bind-event-listener';
10
11
  import { injectIntl } from 'react-intl-next';
11
12
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
12
13
  import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
13
- import { dragToMoveDown, dragToMoveUp, getAriaKeyshortcuts, TooltipContentWithMultipleShortcuts } from '@atlaskit/editor-common/keymaps';
14
+ import { dragToMoveDown, dragToMoveLeft, dragToMoveRight, dragToMoveUp, getAriaKeyshortcuts, TooltipContentWithMultipleShortcuts } from '@atlaskit/editor-common/keymaps';
14
15
  import { blockControlsMessages } from '@atlaskit/editor-common/messages';
15
16
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
16
17
  import DragHandlerIcon from '@atlaskit/icon/glyph/drag-handler';
@@ -20,7 +21,7 @@ import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/el
20
21
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
21
22
  import Tooltip from '@atlaskit/tooltip';
22
23
  import { key } from '../pm-plugins/main';
23
- import { selectNode } from '../utils';
24
+ import { getNestedNodePosition, selectNode } from '../utils';
24
25
  import { getLeftPosition, getTopPosition } from '../utils/drag-handle-positions';
25
26
  import { DRAG_HANDLE_BORDER_RADIUS, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_WIDTH, DRAG_HANDLE_ZINDEX, dragHandleGap, topPositionAdjustment } from './consts';
26
27
  import { dragPreview } from './drag-preview';
@@ -359,7 +360,26 @@ var DragHandleInternal = function DragHandleInternal(_ref) {
359
360
  keymap: dragToMoveDown
360
361
  }] : [{
361
362
  description: formatMessage(blockControlsMessages.dragToMove)
363
+ }, {
364
+ description: formatMessage(blockControlsMessages.moveUp),
365
+ keymap: dragToMoveUp
366
+ }, {
367
+ description: formatMessage(blockControlsMessages.moveDown),
368
+ keymap: dragToMoveDown
362
369
  }];
370
+ var isParentNodeOfTypeLayout;
371
+ if (!isTopLevelNode && handleOptions !== null && handleOptions !== void 0 && handleOptions.isFocused && fg('platform_editor_element_dnd_nested_a11y')) {
372
+ isParentNodeOfTypeLayout = nodeType === 'layoutSection' || view.state.doc.resolve(getNestedNodePosition(view.state)).node().type.name === 'layoutColumn';
373
+ if (isParentNodeOfTypeLayout) {
374
+ helpDescriptors = [].concat(_toConsumableArray(helpDescriptors), [{
375
+ description: formatMessage(blockControlsMessages.moveLeft),
376
+ keymap: dragToMoveLeft
377
+ }, {
378
+ description: formatMessage(blockControlsMessages.moveRight),
379
+ keymap: dragToMoveRight
380
+ }]);
381
+ }
382
+ }
363
383
  var message = helpDescriptors.map(function (descriptor) {
364
384
  return descriptor.keymap ? [descriptor.description, getAriaKeyshortcuts(descriptor.keymap)] : [descriptor.description];
365
385
  }).join('. ');
@@ -0,0 +1,21 @@
1
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
2
+ import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
3
+ export var getNestedNodePosition = function getNestedNodePosition(state) {
4
+ var selection = state.selection;
5
+ var nestedNodePos = selection.$from.before(1);
6
+ if (selection instanceof TextSelection) {
7
+ nestedNodePos = selection.$from.before();
8
+ var $pos = state.doc.resolve(nestedNodePos);
9
+ if ($pos.depth < 1) {
10
+ return nestedNodePos;
11
+ }
12
+ var parentNodeOfSpecificTypes = findParentNodeOfType([state.schema.nodes.bulletList, state.schema.nodes.orderedList, state.schema.nodes.blockquote, state.schema.nodes.taskList])(state.selection);
13
+ if (parentNodeOfSpecificTypes) {
14
+ var parentNodeType = parentNodeOfSpecificTypes.node.type.name;
15
+ nestedNodePos = ['bulletList', 'orderedList'].includes(parentNodeType) ? $pos.before($pos.depth - 1) : ['blockquote', 'taskList'].includes(parentNodeType) ? $pos.before() : nestedNodePos;
16
+ }
17
+ } else {
18
+ nestedNodePos = selection.$from.pos;
19
+ }
20
+ return nestedNodePos;
21
+ };
@@ -1 +1,2 @@
1
- export { getSelection, selectNode } from './getSelection';
1
+ export { getSelection, selectNode } from './getSelection';
2
+ export { getNestedNodePosition } from './getNestedNodePosition';
@@ -1,3 +1,3 @@
1
1
  import type { Command, ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
2
  import type { BlockControlsPlugin } from '../types';
3
- export declare const showDragHandleAtSelection: (api?: ExtractInjectionAPI<BlockControlsPlugin>) => Command;
3
+ export declare const showDragHandleAtSelection: (api?: ExtractInjectionAPI<BlockControlsPlugin>, shouldFocusParentNode?: boolean) => Command;
@@ -1,4 +1,6 @@
1
1
  export declare enum DIRECTION {
2
2
  UP = "up",
3
- DOWN = "down"
3
+ DOWN = "down",
4
+ LEFT = "left",
5
+ RIGHT = "right"
4
6
  }
@@ -0,0 +1,2 @@
1
+ import { type EditorState } from '@atlaskit/editor-prosemirror/state';
2
+ export declare const getNestedNodePosition: (state: EditorState) => number;
@@ -1 +1,2 @@
1
1
  export { getSelection, selectNode } from './getSelection';
2
+ export { getNestedNodePosition } from './getNestedNodePosition';
@@ -1,3 +1,3 @@
1
1
  import type { Command, ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
2
  import type { BlockControlsPlugin } from '../types';
3
- export declare const showDragHandleAtSelection: (api?: ExtractInjectionAPI<BlockControlsPlugin>) => Command;
3
+ export declare const showDragHandleAtSelection: (api?: ExtractInjectionAPI<BlockControlsPlugin>, shouldFocusParentNode?: boolean) => Command;
@@ -1,4 +1,6 @@
1
1
  export declare enum DIRECTION {
2
2
  UP = "up",
3
- DOWN = "down"
3
+ DOWN = "down",
4
+ LEFT = "left",
5
+ RIGHT = "right"
4
6
  }
@@ -0,0 +1,2 @@
1
+ import { type EditorState } from '@atlaskit/editor-prosemirror/state';
2
+ export declare const getNestedNodePosition: (state: EditorState) => number;
@@ -1 +1,2 @@
1
1
  export { getSelection, selectNode } from './getSelection';
2
+ export { getNestedNodePosition } from './getNestedNodePosition';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-controls",
3
- "version": "2.1.11",
3
+ "version": "2.2.1",
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": "^40.9.0",
34
- "@atlaskit/editor-common": "^93.0.0",
34
+ "@atlaskit/editor-common": "^93.1.0",
35
35
  "@atlaskit/editor-plugin-accessibility-utils": "^1.2.0",
36
36
  "@atlaskit/editor-plugin-analytics": "^1.8.0",
37
37
  "@atlaskit/editor-plugin-editor-disabled": "^1.3.0",
@@ -41,14 +41,14 @@
41
41
  "@atlaskit/editor-prosemirror": "6.0.0",
42
42
  "@atlaskit/editor-shared-styles": "^3.0.0",
43
43
  "@atlaskit/editor-tables": "^2.8.0",
44
- "@atlaskit/icon": "^22.20.0",
44
+ "@atlaskit/icon": "^22.22.0",
45
45
  "@atlaskit/platform-feature-flags": "^0.3.0",
46
46
  "@atlaskit/pragmatic-drag-and-drop": "^1.3.0",
47
47
  "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^1.4.0",
48
48
  "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^1.1.0",
49
49
  "@atlaskit/primitives": "^12.2.0",
50
50
  "@atlaskit/theme": "^13.0.0",
51
- "@atlaskit/tmp-editor-statsig": "^2.2.0",
51
+ "@atlaskit/tmp-editor-statsig": "^2.3.0",
52
52
  "@atlaskit/tokens": "^2.0.0",
53
53
  "@atlaskit/tooltip": "^18.8.0",
54
54
  "@babel/runtime": "^7.0.0",
@@ -147,6 +147,9 @@
147
147
  },
148
148
  "confluence_frontend_page_title_enter_improvements": {
149
149
  "type": "boolean"
150
+ },
151
+ "platform_editor_element_dnd_nested_a11y": {
152
+ "type": "boolean"
150
153
  }
151
154
  }
152
155
  }