@atlaskit/editor-plugin-block-controls 7.2.7 → 7.2.9
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.
- package/CHANGELOG.md +15 -0
- package/dist/cjs/editor-commands/move-node.js +1 -1
- package/dist/cjs/editor-commands/show-drag-handle.js +56 -9
- package/dist/cjs/pm-plugins/keymap.js +2 -2
- package/dist/cjs/pm-plugins/utils/getNestedNodePosition.js +48 -1
- package/dist/cjs/pm-plugins/utils/validation.js +17 -19
- package/dist/es2019/editor-commands/move-node.js +1 -1
- package/dist/es2019/editor-commands/show-drag-handle.js +59 -10
- package/dist/es2019/pm-plugins/keymap.js +2 -2
- package/dist/es2019/pm-plugins/utils/getNestedNodePosition.js +49 -0
- package/dist/es2019/pm-plugins/utils/validation.js +17 -19
- package/dist/esm/editor-commands/move-node.js +1 -1
- package/dist/esm/editor-commands/show-drag-handle.js +57 -10
- package/dist/esm/pm-plugins/keymap.js +2 -2
- package/dist/esm/pm-plugins/utils/getNestedNodePosition.js +47 -0
- package/dist/esm/pm-plugins/utils/validation.js +17 -19
- package/dist/types/pm-plugins/utils/getNestedNodePosition.d.ts +9 -0
- package/dist/types-ts4.5/pm-plugins/utils/getNestedNodePosition.d.ts +9 -0
- package/package.json +1 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-block-controls
|
|
2
2
|
|
|
3
|
+
## 7.2.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`3a41420ddfc6e`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/3a41420ddfc6e) -
|
|
8
|
+
Clean up platform_editor_drag_layout_column_into_nodes
|
|
9
|
+
|
|
10
|
+
## 7.2.8
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- [`435745247f7ef`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/435745247f7ef) -
|
|
15
|
+
[ED-29337] Fix drag handle cannot be focus via shorcut when platform_editor_native_anchor_support
|
|
16
|
+
is enabled
|
|
17
|
+
|
|
3
18
|
## 7.2.7
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
|
@@ -91,7 +91,7 @@ var isDragLayoutColumnIntoSupportedNodes = function isDragLayoutColumnIntoSuppor
|
|
|
91
91
|
var _$from$nodeAfter;
|
|
92
92
|
var isTopLevel = $to.depth === 0;
|
|
93
93
|
var isDragIntoNodes = nodesSupportDragLayoutColumnInto.includes($to.parent.type.name);
|
|
94
|
-
var supportedCondition =
|
|
94
|
+
var supportedCondition = isDragIntoNodes || isTopLevel;
|
|
95
95
|
return ((_$from$nodeAfter = $from.nodeAfter) === null || _$from$nodeAfter === void 0 ? void 0 : _$from$nodeAfter.type.name) === 'layoutColumn' && $from.parent.type.name === 'layoutSection' && supportedCondition;
|
|
96
96
|
};
|
|
97
97
|
|
|
@@ -5,9 +5,11 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.showDragHandleAtSelection = void 0;
|
|
7
7
|
var _utils = require("@atlaskit/editor-prosemirror/utils");
|
|
8
|
+
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
8
9
|
var _decorationsAnchor = require("../pm-plugins/decorations-anchor");
|
|
9
10
|
var _main = require("../pm-plugins/main");
|
|
10
11
|
var _getNestedNodePosition = require("../pm-plugins/utils/getNestedNodePosition");
|
|
12
|
+
var _domAttrName = require("../ui/utils/dom-attr-name");
|
|
11
13
|
var findParentPosForHandle = function findParentPosForHandle(state) {
|
|
12
14
|
var _activeNode$handleOpt;
|
|
13
15
|
var $from = state.selection.$from;
|
|
@@ -37,7 +39,15 @@ var findParentPosForHandle = function findParentPosForHandle(state) {
|
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
// else find closest parent node
|
|
40
|
-
return (0,
|
|
42
|
+
return (0, _expValEquals.expValEquals)('platform_editor_native_anchor_support', 'isEnabled', true) ?
|
|
43
|
+
// With native anchor enabled, all nodes have anchor name attribute despite no drag handle support, e.g. listItem, caption,
|
|
44
|
+
// as opposed to old approach, node decoration is only added to the node that have drag handle,
|
|
45
|
+
// hence, we need to return the exact position of the node that can have drag handle
|
|
46
|
+
(0, _getNestedNodePosition.getNestedNodeStartingPosition)({
|
|
47
|
+
selection: state.selection,
|
|
48
|
+
schema: state.schema,
|
|
49
|
+
resolve: state.doc.resolve.bind(state.doc)
|
|
50
|
+
}) : (0, _getNestedNodePosition.getNestedNodePosition)({
|
|
41
51
|
selection: state.selection,
|
|
42
52
|
schema: state.schema,
|
|
43
53
|
resolve: state.doc.resolve.bind(state.doc)
|
|
@@ -78,15 +88,52 @@ var findNextAnchorDecoration = function findNextAnchorDecoration(state) {
|
|
|
78
88
|
// return the closest decoration to the node
|
|
79
89
|
return nodeDecorations[0];
|
|
80
90
|
};
|
|
91
|
+
var findNextAnchorNode = function findNextAnchorNode(view) {
|
|
92
|
+
var nextHandleNodePos = findParentPosForHandle(view.state);
|
|
93
|
+
if (nextHandleNodePos === undefined) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
var dom = view.nodeDOM(nextHandleNodePos);
|
|
97
|
+
if (!(dom instanceof HTMLElement)) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
var nodeDOM = dom.closest("[".concat(_domAttrName.NODE_ANCHOR_ATTR_NAME, "]"));
|
|
101
|
+
if (!nodeDOM) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
var nodeType = nodeDOM === null || nodeDOM === void 0 ? void 0 : nodeDOM.getAttribute(_domAttrName.NODE_NODE_TYPE_ATTR_NAME);
|
|
105
|
+
var anchorName = nodeDOM === null || nodeDOM === void 0 ? void 0 : nodeDOM.getAttribute(_domAttrName.NODE_ANCHOR_ATTR_NAME);
|
|
106
|
+
if (nodeType && anchorName) {
|
|
107
|
+
return {
|
|
108
|
+
pos: nextHandleNodePos,
|
|
109
|
+
nodeType: nodeType,
|
|
110
|
+
anchorName: anchorName
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
};
|
|
81
114
|
var showDragHandleAtSelection = exports.showDragHandleAtSelection = function showDragHandleAtSelection(api) {
|
|
82
|
-
return function (state) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
115
|
+
return function (state, _, view) {
|
|
116
|
+
if (view && (0, _expValEquals.expValEquals)('platform_editor_native_anchor_support', 'isEnabled', true)) {
|
|
117
|
+
var anchorNode = findNextAnchorNode(view);
|
|
118
|
+
if (api && anchorNode) {
|
|
119
|
+
var pos = anchorNode.pos,
|
|
120
|
+
anchorName = anchorNode.anchorName,
|
|
121
|
+
nodeType = anchorNode.nodeType;
|
|
122
|
+
api.core.actions.execute(api.blockControls.commands.showDragHandleAt(pos, anchorName, nodeType, {
|
|
123
|
+
isFocused: true
|
|
124
|
+
}));
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
128
|
+
} else {
|
|
129
|
+
var decoration = findNextAnchorDecoration(state);
|
|
130
|
+
if (api && decoration) {
|
|
131
|
+
api.core.actions.execute(api.blockControls.commands.showDragHandleAt(decoration.from, decoration.spec.anchorName, decoration.spec.nodeTypeWithLevel, {
|
|
132
|
+
isFocused: true
|
|
133
|
+
}));
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
89
137
|
}
|
|
90
|
-
return false;
|
|
91
138
|
};
|
|
92
139
|
};
|
|
@@ -15,8 +15,8 @@ function keymapList(api, formatMessage) {
|
|
|
15
15
|
(0, _keymaps.bindKeymapWithCommand)(
|
|
16
16
|
// Ignored via go/ees005
|
|
17
17
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
18
|
-
_keymaps.showElementDragHandle.common, function (state) {
|
|
19
|
-
(0, _showDragHandle.showDragHandleAtSelection)(api)(state);
|
|
18
|
+
_keymaps.showElementDragHandle.common, function (state, dispatch, view) {
|
|
19
|
+
(0, _showDragHandle.showDragHandleAtSelection)(api)(state, dispatch, view);
|
|
20
20
|
//we always want to handle this shortcut to prevent default browser special char insert when option + alphabetical key is used
|
|
21
21
|
return true;
|
|
22
22
|
}, keymapList);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.getNestedNodePosition = void 0;
|
|
6
|
+
exports.getNestedNodeStartingPosition = exports.getNestedNodePosition = void 0;
|
|
7
7
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
8
8
|
var _utils = require("@atlaskit/editor-prosemirror/utils");
|
|
9
9
|
var getNestedNodePosition = exports.getNestedNodePosition = function getNestedNodePosition(_ref) {
|
|
@@ -26,4 +26,51 @@ var getNestedNodePosition = exports.getNestedNodePosition = function getNestedNo
|
|
|
26
26
|
nestedNodePos = selection.$from.pos;
|
|
27
27
|
}
|
|
28
28
|
return nestedNodePos;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
* @returns starting position of nested node that drag handle can be shown next to
|
|
34
|
+
*/
|
|
35
|
+
var getNestedNodeStartingPosition = exports.getNestedNodeStartingPosition = function getNestedNodeStartingPosition(_ref2) {
|
|
36
|
+
var selection = _ref2.selection,
|
|
37
|
+
schema = _ref2.schema,
|
|
38
|
+
resolve = _ref2.resolve;
|
|
39
|
+
var nestedNodePos = selection.$from.before(1);
|
|
40
|
+
if (selection instanceof _state.TextSelection) {
|
|
41
|
+
nestedNodePos = selection.$from.before();
|
|
42
|
+
var $pos = resolve(nestedNodePos);
|
|
43
|
+
if ($pos.depth < 1) {
|
|
44
|
+
return nestedNodePos;
|
|
45
|
+
}
|
|
46
|
+
var _schema$nodes = schema.nodes,
|
|
47
|
+
bulletList = _schema$nodes.bulletList,
|
|
48
|
+
orderedList = _schema$nodes.orderedList,
|
|
49
|
+
taskList = _schema$nodes.taskList,
|
|
50
|
+
decisionList = _schema$nodes.decisionList,
|
|
51
|
+
caption = _schema$nodes.caption;
|
|
52
|
+
var isInList = (0, _utils.findParentNodeOfType)([bulletList, orderedList, taskList])(selection);
|
|
53
|
+
var isInNodeWithoutDragHandle = (0, _utils.findParentNodeOfType)([caption, decisionList])(selection);
|
|
54
|
+
if (isInList) {
|
|
55
|
+
// Only show drag handle at outermost list parent
|
|
56
|
+
nestedNodePos = _getOutermostListPos($pos, resolve);
|
|
57
|
+
} else if (isInNodeWithoutDragHandle) {
|
|
58
|
+
// return the position of their parent if there should be no drag handle before the node
|
|
59
|
+
nestedNodePos = $pos.before();
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
nestedNodePos = selection.$from.pos;
|
|
63
|
+
}
|
|
64
|
+
return nestedNodePos;
|
|
65
|
+
};
|
|
66
|
+
var _getOutermostListPos = function getOutermostListPos($pos, resolve) {
|
|
67
|
+
if ($pos.depth === 0) {
|
|
68
|
+
return $pos.pos;
|
|
69
|
+
}
|
|
70
|
+
var parentPos = $pos.before();
|
|
71
|
+
var parentNode = $pos.parent;
|
|
72
|
+
if (parentNode && ['bulletList', 'listItem', 'orderedList', 'taskList', 'taskItem'].includes(parentNode.type.name)) {
|
|
73
|
+
return _getOutermostListPos(resolve(parentPos), resolve);
|
|
74
|
+
}
|
|
75
|
+
return $pos.pos;
|
|
29
76
|
};
|
|
@@ -121,26 +121,24 @@ function canMoveNodeToIndex(destParent, indexIntoParent, srcNode, $destNodePos,
|
|
|
121
121
|
if ((destNode === null || destNode === void 0 ? void 0 : destNode.type) === layoutSection || destParentNodeType === doc) {
|
|
122
122
|
return true;
|
|
123
123
|
}
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
return canCreateNodeWithContentInsideAnotherNode([tableCell, tableHeader], convertedFragment);
|
|
134
|
-
}
|
|
135
|
-
if (destParentNodeType === panel) {
|
|
136
|
-
return canCreateNodeWithContentInsideAnotherNode([panel], layoutColumnContent);
|
|
137
|
-
}
|
|
138
|
-
if (destParentNodeType === expand) {
|
|
139
|
-
return canCreateNodeWithContentInsideAnotherNode([expand], layoutColumnContent);
|
|
140
|
-
}
|
|
141
|
-
if (destParentNodeType === nestedExpand) {
|
|
142
|
-
return canCreateNodeWithContentInsideAnotherNode([nestedExpand], layoutColumnContent);
|
|
124
|
+
if (destParentNodeType === tableCell || destParentNodeType === tableHeader) {
|
|
125
|
+
var contentContainsExpand = (0, _utils.findChildrenByType)(srcNode, expand).length > 0;
|
|
126
|
+
//convert expand to nestedExpand if there are expands inside the layout column
|
|
127
|
+
// otherwise, the createChecked will fail as expand is not a valid child of tableCell/tableHeader, but nestedExpand is
|
|
128
|
+
var convertedFragment = contentContainsExpand ? transformFragmentExpandToNestedExpand(layoutColumnContent) : layoutColumnContent;
|
|
129
|
+
if (!convertedFragment) {
|
|
130
|
+
return false;
|
|
143
131
|
}
|
|
132
|
+
return canCreateNodeWithContentInsideAnotherNode([tableCell, tableHeader], convertedFragment);
|
|
133
|
+
}
|
|
134
|
+
if (destParentNodeType === panel) {
|
|
135
|
+
return canCreateNodeWithContentInsideAnotherNode([panel], layoutColumnContent);
|
|
136
|
+
}
|
|
137
|
+
if (destParentNodeType === expand) {
|
|
138
|
+
return canCreateNodeWithContentInsideAnotherNode([expand], layoutColumnContent);
|
|
139
|
+
}
|
|
140
|
+
if (destParentNodeType === nestedExpand) {
|
|
141
|
+
return canCreateNodeWithContentInsideAnotherNode([nestedExpand], layoutColumnContent);
|
|
144
142
|
}
|
|
145
143
|
}
|
|
146
144
|
|
|
@@ -84,7 +84,7 @@ const isDragLayoutColumnIntoSupportedNodes = ($from, $to) => {
|
|
|
84
84
|
var _$from$nodeAfter;
|
|
85
85
|
const isTopLevel = $to.depth === 0;
|
|
86
86
|
const isDragIntoNodes = nodesSupportDragLayoutColumnInto.includes($to.parent.type.name);
|
|
87
|
-
const supportedCondition =
|
|
87
|
+
const supportedCondition = isDragIntoNodes || isTopLevel;
|
|
88
88
|
return ((_$from$nodeAfter = $from.nodeAfter) === null || _$from$nodeAfter === void 0 ? void 0 : _$from$nodeAfter.type.name) === 'layoutColumn' && $from.parent.type.name === 'layoutSection' && supportedCondition;
|
|
89
89
|
};
|
|
90
90
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
2
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
2
3
|
import { findNodeDecs } from '../pm-plugins/decorations-anchor';
|
|
3
4
|
import { getDecorations, key } from '../pm-plugins/main';
|
|
4
|
-
import { getNestedNodePosition } from '../pm-plugins/utils/getNestedNodePosition';
|
|
5
|
+
import { getNestedNodePosition, getNestedNodeStartingPosition } from '../pm-plugins/utils/getNestedNodePosition';
|
|
6
|
+
import { NODE_ANCHOR_ATTR_NAME, NODE_NODE_TYPE_ATTR_NAME } from '../ui/utils/dom-attr-name';
|
|
5
7
|
const findParentPosForHandle = state => {
|
|
6
8
|
var _activeNode$handleOpt;
|
|
7
9
|
const {
|
|
@@ -36,7 +38,15 @@ const findParentPosForHandle = state => {
|
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
// else find closest parent node
|
|
39
|
-
return
|
|
41
|
+
return expValEquals('platform_editor_native_anchor_support', 'isEnabled', true) ?
|
|
42
|
+
// With native anchor enabled, all nodes have anchor name attribute despite no drag handle support, e.g. listItem, caption,
|
|
43
|
+
// as opposed to old approach, node decoration is only added to the node that have drag handle,
|
|
44
|
+
// hence, we need to return the exact position of the node that can have drag handle
|
|
45
|
+
getNestedNodeStartingPosition({
|
|
46
|
+
selection: state.selection,
|
|
47
|
+
schema: state.schema,
|
|
48
|
+
resolve: state.doc.resolve.bind(state.doc)
|
|
49
|
+
}) : getNestedNodePosition({
|
|
40
50
|
selection: state.selection,
|
|
41
51
|
schema: state.schema,
|
|
42
52
|
resolve: state.doc.resolve.bind(state.doc)
|
|
@@ -77,13 +87,52 @@ const findNextAnchorDecoration = state => {
|
|
|
77
87
|
// return the closest decoration to the node
|
|
78
88
|
return nodeDecorations[0];
|
|
79
89
|
};
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
const findNextAnchorNode = view => {
|
|
91
|
+
const nextHandleNodePos = findParentPosForHandle(view.state);
|
|
92
|
+
if (nextHandleNodePos === undefined) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
const dom = view.nodeDOM(nextHandleNodePos);
|
|
96
|
+
if (!(dom instanceof HTMLElement)) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
const nodeDOM = dom.closest(`[${NODE_ANCHOR_ATTR_NAME}]`);
|
|
100
|
+
if (!nodeDOM) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const nodeType = nodeDOM === null || nodeDOM === void 0 ? void 0 : nodeDOM.getAttribute(NODE_NODE_TYPE_ATTR_NAME);
|
|
104
|
+
const anchorName = nodeDOM === null || nodeDOM === void 0 ? void 0 : nodeDOM.getAttribute(NODE_ANCHOR_ATTR_NAME);
|
|
105
|
+
if (nodeType && anchorName) {
|
|
106
|
+
return {
|
|
107
|
+
pos: nextHandleNodePos,
|
|
108
|
+
nodeType,
|
|
109
|
+
anchorName
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
export const showDragHandleAtSelection = api => (state, _, view) => {
|
|
114
|
+
if (view && expValEquals('platform_editor_native_anchor_support', 'isEnabled', true)) {
|
|
115
|
+
const anchorNode = findNextAnchorNode(view);
|
|
116
|
+
if (api && anchorNode) {
|
|
117
|
+
const {
|
|
118
|
+
pos,
|
|
119
|
+
anchorName,
|
|
120
|
+
nodeType
|
|
121
|
+
} = anchorNode;
|
|
122
|
+
api.core.actions.execute(api.blockControls.commands.showDragHandleAt(pos, anchorName, nodeType, {
|
|
123
|
+
isFocused: true
|
|
124
|
+
}));
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
128
|
+
} else {
|
|
129
|
+
const decoration = findNextAnchorDecoration(state);
|
|
130
|
+
if (api && decoration) {
|
|
131
|
+
api.core.actions.execute(api.blockControls.commands.showDragHandleAt(decoration.from, decoration.spec.anchorName, decoration.spec.nodeTypeWithLevel, {
|
|
132
|
+
isFocused: true
|
|
133
|
+
}));
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
87
137
|
}
|
|
88
|
-
return false;
|
|
89
138
|
};
|
|
@@ -9,8 +9,8 @@ function keymapList(api, formatMessage) {
|
|
|
9
9
|
bindKeymapWithCommand(
|
|
10
10
|
// Ignored via go/ees005
|
|
11
11
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
12
|
-
showElementDragHandle.common, state => {
|
|
13
|
-
showDragHandleAtSelection(api)(state);
|
|
12
|
+
showElementDragHandle.common, (state, dispatch, view) => {
|
|
13
|
+
showDragHandleAtSelection(api)(state, dispatch, view);
|
|
14
14
|
//we always want to handle this shortcut to prevent default browser special char insert when option + alphabetical key is used
|
|
15
15
|
return true;
|
|
16
16
|
}, keymapList);
|
|
@@ -21,4 +21,53 @@ export const getNestedNodePosition = ({
|
|
|
21
21
|
nestedNodePos = selection.$from.pos;
|
|
22
22
|
}
|
|
23
23
|
return nestedNodePos;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
* @returns starting position of nested node that drag handle can be shown next to
|
|
29
|
+
*/
|
|
30
|
+
export const getNestedNodeStartingPosition = ({
|
|
31
|
+
selection,
|
|
32
|
+
schema,
|
|
33
|
+
resolve
|
|
34
|
+
}) => {
|
|
35
|
+
let nestedNodePos = selection.$from.before(1);
|
|
36
|
+
if (selection instanceof TextSelection) {
|
|
37
|
+
nestedNodePos = selection.$from.before();
|
|
38
|
+
const $pos = resolve(nestedNodePos);
|
|
39
|
+
if ($pos.depth < 1) {
|
|
40
|
+
return nestedNodePos;
|
|
41
|
+
}
|
|
42
|
+
const {
|
|
43
|
+
bulletList,
|
|
44
|
+
orderedList,
|
|
45
|
+
taskList,
|
|
46
|
+
decisionList,
|
|
47
|
+
caption
|
|
48
|
+
} = schema.nodes;
|
|
49
|
+
const isInList = findParentNodeOfType([bulletList, orderedList, taskList])(selection);
|
|
50
|
+
const isInNodeWithoutDragHandle = findParentNodeOfType([caption, decisionList])(selection);
|
|
51
|
+
if (isInList) {
|
|
52
|
+
// Only show drag handle at outermost list parent
|
|
53
|
+
nestedNodePos = getOutermostListPos($pos, resolve);
|
|
54
|
+
} else if (isInNodeWithoutDragHandle) {
|
|
55
|
+
// return the position of their parent if there should be no drag handle before the node
|
|
56
|
+
nestedNodePos = $pos.before();
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
nestedNodePos = selection.$from.pos;
|
|
60
|
+
}
|
|
61
|
+
return nestedNodePos;
|
|
62
|
+
};
|
|
63
|
+
const getOutermostListPos = ($pos, resolve) => {
|
|
64
|
+
if ($pos.depth === 0) {
|
|
65
|
+
return $pos.pos;
|
|
66
|
+
}
|
|
67
|
+
const parentPos = $pos.before();
|
|
68
|
+
const parentNode = $pos.parent;
|
|
69
|
+
if (parentNode && ['bulletList', 'listItem', 'orderedList', 'taskList', 'taskItem'].includes(parentNode.type.name)) {
|
|
70
|
+
return getOutermostListPos(resolve(parentPos), resolve);
|
|
71
|
+
}
|
|
72
|
+
return $pos.pos;
|
|
24
73
|
};
|
|
@@ -112,26 +112,24 @@ export function canMoveNodeToIndex(destParent, indexIntoParent, srcNode, $destNo
|
|
|
112
112
|
if ((destNode === null || destNode === void 0 ? void 0 : destNode.type) === layoutSection || destParentNodeType === doc) {
|
|
113
113
|
return true;
|
|
114
114
|
}
|
|
115
|
-
if (
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
return canCreateNodeWithContentInsideAnotherNode([tableCell, tableHeader], convertedFragment);
|
|
125
|
-
}
|
|
126
|
-
if (destParentNodeType === panel) {
|
|
127
|
-
return canCreateNodeWithContentInsideAnotherNode([panel], layoutColumnContent);
|
|
128
|
-
}
|
|
129
|
-
if (destParentNodeType === expand) {
|
|
130
|
-
return canCreateNodeWithContentInsideAnotherNode([expand], layoutColumnContent);
|
|
131
|
-
}
|
|
132
|
-
if (destParentNodeType === nestedExpand) {
|
|
133
|
-
return canCreateNodeWithContentInsideAnotherNode([nestedExpand], layoutColumnContent);
|
|
115
|
+
if (destParentNodeType === tableCell || destParentNodeType === tableHeader) {
|
|
116
|
+
const contentContainsExpand = findChildrenByType(srcNode, expand).length > 0;
|
|
117
|
+
//convert expand to nestedExpand if there are expands inside the layout column
|
|
118
|
+
// otherwise, the createChecked will fail as expand is not a valid child of tableCell/tableHeader, but nestedExpand is
|
|
119
|
+
const convertedFragment = contentContainsExpand ? transformFragmentExpandToNestedExpand(layoutColumnContent) : layoutColumnContent;
|
|
120
|
+
if (!convertedFragment) {
|
|
121
|
+
return false;
|
|
134
122
|
}
|
|
123
|
+
return canCreateNodeWithContentInsideAnotherNode([tableCell, tableHeader], convertedFragment);
|
|
124
|
+
}
|
|
125
|
+
if (destParentNodeType === panel) {
|
|
126
|
+
return canCreateNodeWithContentInsideAnotherNode([panel], layoutColumnContent);
|
|
127
|
+
}
|
|
128
|
+
if (destParentNodeType === expand) {
|
|
129
|
+
return canCreateNodeWithContentInsideAnotherNode([expand], layoutColumnContent);
|
|
130
|
+
}
|
|
131
|
+
if (destParentNodeType === nestedExpand) {
|
|
132
|
+
return canCreateNodeWithContentInsideAnotherNode([nestedExpand], layoutColumnContent);
|
|
135
133
|
}
|
|
136
134
|
}
|
|
137
135
|
|
|
@@ -85,7 +85,7 @@ var isDragLayoutColumnIntoSupportedNodes = function isDragLayoutColumnIntoSuppor
|
|
|
85
85
|
var _$from$nodeAfter;
|
|
86
86
|
var isTopLevel = $to.depth === 0;
|
|
87
87
|
var isDragIntoNodes = nodesSupportDragLayoutColumnInto.includes($to.parent.type.name);
|
|
88
|
-
var supportedCondition =
|
|
88
|
+
var supportedCondition = isDragIntoNodes || isTopLevel;
|
|
89
89
|
return ((_$from$nodeAfter = $from.nodeAfter) === null || _$from$nodeAfter === void 0 ? void 0 : _$from$nodeAfter.type.name) === 'layoutColumn' && $from.parent.type.name === 'layoutSection' && supportedCondition;
|
|
90
90
|
};
|
|
91
91
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
2
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
2
3
|
import { findNodeDecs } from '../pm-plugins/decorations-anchor';
|
|
3
4
|
import { getDecorations, key } from '../pm-plugins/main';
|
|
4
|
-
import { getNestedNodePosition } from '../pm-plugins/utils/getNestedNodePosition';
|
|
5
|
+
import { getNestedNodePosition, getNestedNodeStartingPosition } from '../pm-plugins/utils/getNestedNodePosition';
|
|
6
|
+
import { NODE_ANCHOR_ATTR_NAME, NODE_NODE_TYPE_ATTR_NAME } from '../ui/utils/dom-attr-name';
|
|
5
7
|
var findParentPosForHandle = function findParentPosForHandle(state) {
|
|
6
8
|
var _activeNode$handleOpt;
|
|
7
9
|
var $from = state.selection.$from;
|
|
@@ -31,7 +33,15 @@ var findParentPosForHandle = function findParentPosForHandle(state) {
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
// else find closest parent node
|
|
34
|
-
return
|
|
36
|
+
return expValEquals('platform_editor_native_anchor_support', 'isEnabled', true) ?
|
|
37
|
+
// With native anchor enabled, all nodes have anchor name attribute despite no drag handle support, e.g. listItem, caption,
|
|
38
|
+
// as opposed to old approach, node decoration is only added to the node that have drag handle,
|
|
39
|
+
// hence, we need to return the exact position of the node that can have drag handle
|
|
40
|
+
getNestedNodeStartingPosition({
|
|
41
|
+
selection: state.selection,
|
|
42
|
+
schema: state.schema,
|
|
43
|
+
resolve: state.doc.resolve.bind(state.doc)
|
|
44
|
+
}) : getNestedNodePosition({
|
|
35
45
|
selection: state.selection,
|
|
36
46
|
schema: state.schema,
|
|
37
47
|
resolve: state.doc.resolve.bind(state.doc)
|
|
@@ -72,15 +82,52 @@ var findNextAnchorDecoration = function findNextAnchorDecoration(state) {
|
|
|
72
82
|
// return the closest decoration to the node
|
|
73
83
|
return nodeDecorations[0];
|
|
74
84
|
};
|
|
85
|
+
var findNextAnchorNode = function findNextAnchorNode(view) {
|
|
86
|
+
var nextHandleNodePos = findParentPosForHandle(view.state);
|
|
87
|
+
if (nextHandleNodePos === undefined) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
var dom = view.nodeDOM(nextHandleNodePos);
|
|
91
|
+
if (!(dom instanceof HTMLElement)) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
var nodeDOM = dom.closest("[".concat(NODE_ANCHOR_ATTR_NAME, "]"));
|
|
95
|
+
if (!nodeDOM) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
var nodeType = nodeDOM === null || nodeDOM === void 0 ? void 0 : nodeDOM.getAttribute(NODE_NODE_TYPE_ATTR_NAME);
|
|
99
|
+
var anchorName = nodeDOM === null || nodeDOM === void 0 ? void 0 : nodeDOM.getAttribute(NODE_ANCHOR_ATTR_NAME);
|
|
100
|
+
if (nodeType && anchorName) {
|
|
101
|
+
return {
|
|
102
|
+
pos: nextHandleNodePos,
|
|
103
|
+
nodeType: nodeType,
|
|
104
|
+
anchorName: anchorName
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
};
|
|
75
108
|
export var showDragHandleAtSelection = function showDragHandleAtSelection(api) {
|
|
76
|
-
return function (state) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
109
|
+
return function (state, _, view) {
|
|
110
|
+
if (view && expValEquals('platform_editor_native_anchor_support', 'isEnabled', true)) {
|
|
111
|
+
var anchorNode = findNextAnchorNode(view);
|
|
112
|
+
if (api && anchorNode) {
|
|
113
|
+
var pos = anchorNode.pos,
|
|
114
|
+
anchorName = anchorNode.anchorName,
|
|
115
|
+
nodeType = anchorNode.nodeType;
|
|
116
|
+
api.core.actions.execute(api.blockControls.commands.showDragHandleAt(pos, anchorName, nodeType, {
|
|
117
|
+
isFocused: true
|
|
118
|
+
}));
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
} else {
|
|
123
|
+
var decoration = findNextAnchorDecoration(state);
|
|
124
|
+
if (api && decoration) {
|
|
125
|
+
api.core.actions.execute(api.blockControls.commands.showDragHandleAt(decoration.from, decoration.spec.anchorName, decoration.spec.nodeTypeWithLevel, {
|
|
126
|
+
isFocused: true
|
|
127
|
+
}));
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
83
131
|
}
|
|
84
|
-
return false;
|
|
85
132
|
};
|
|
86
133
|
};
|
|
@@ -9,8 +9,8 @@ function keymapList(api, formatMessage) {
|
|
|
9
9
|
bindKeymapWithCommand(
|
|
10
10
|
// Ignored via go/ees005
|
|
11
11
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
12
|
-
showElementDragHandle.common, function (state) {
|
|
13
|
-
showDragHandleAtSelection(api)(state);
|
|
12
|
+
showElementDragHandle.common, function (state, dispatch, view) {
|
|
13
|
+
showDragHandleAtSelection(api)(state, dispatch, view);
|
|
14
14
|
//we always want to handle this shortcut to prevent default browser special char insert when option + alphabetical key is used
|
|
15
15
|
return true;
|
|
16
16
|
}, keymapList);
|
|
@@ -20,4 +20,51 @@ export var getNestedNodePosition = function getNestedNodePosition(_ref) {
|
|
|
20
20
|
nestedNodePos = selection.$from.pos;
|
|
21
21
|
}
|
|
22
22
|
return nestedNodePos;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
* @returns starting position of nested node that drag handle can be shown next to
|
|
28
|
+
*/
|
|
29
|
+
export var getNestedNodeStartingPosition = function getNestedNodeStartingPosition(_ref2) {
|
|
30
|
+
var selection = _ref2.selection,
|
|
31
|
+
schema = _ref2.schema,
|
|
32
|
+
resolve = _ref2.resolve;
|
|
33
|
+
var nestedNodePos = selection.$from.before(1);
|
|
34
|
+
if (selection instanceof TextSelection) {
|
|
35
|
+
nestedNodePos = selection.$from.before();
|
|
36
|
+
var $pos = resolve(nestedNodePos);
|
|
37
|
+
if ($pos.depth < 1) {
|
|
38
|
+
return nestedNodePos;
|
|
39
|
+
}
|
|
40
|
+
var _schema$nodes = schema.nodes,
|
|
41
|
+
bulletList = _schema$nodes.bulletList,
|
|
42
|
+
orderedList = _schema$nodes.orderedList,
|
|
43
|
+
taskList = _schema$nodes.taskList,
|
|
44
|
+
decisionList = _schema$nodes.decisionList,
|
|
45
|
+
caption = _schema$nodes.caption;
|
|
46
|
+
var isInList = findParentNodeOfType([bulletList, orderedList, taskList])(selection);
|
|
47
|
+
var isInNodeWithoutDragHandle = findParentNodeOfType([caption, decisionList])(selection);
|
|
48
|
+
if (isInList) {
|
|
49
|
+
// Only show drag handle at outermost list parent
|
|
50
|
+
nestedNodePos = _getOutermostListPos($pos, resolve);
|
|
51
|
+
} else if (isInNodeWithoutDragHandle) {
|
|
52
|
+
// return the position of their parent if there should be no drag handle before the node
|
|
53
|
+
nestedNodePos = $pos.before();
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
nestedNodePos = selection.$from.pos;
|
|
57
|
+
}
|
|
58
|
+
return nestedNodePos;
|
|
59
|
+
};
|
|
60
|
+
var _getOutermostListPos = function getOutermostListPos($pos, resolve) {
|
|
61
|
+
if ($pos.depth === 0) {
|
|
62
|
+
return $pos.pos;
|
|
63
|
+
}
|
|
64
|
+
var parentPos = $pos.before();
|
|
65
|
+
var parentNode = $pos.parent;
|
|
66
|
+
if (parentNode && ['bulletList', 'listItem', 'orderedList', 'taskList', 'taskItem'].includes(parentNode.type.name)) {
|
|
67
|
+
return _getOutermostListPos(resolve(parentPos), resolve);
|
|
68
|
+
}
|
|
69
|
+
return $pos.pos;
|
|
23
70
|
};
|
|
@@ -111,26 +111,24 @@ export function canMoveNodeToIndex(destParent, indexIntoParent, srcNode, $destNo
|
|
|
111
111
|
if ((destNode === null || destNode === void 0 ? void 0 : destNode.type) === layoutSection || destParentNodeType === doc) {
|
|
112
112
|
return true;
|
|
113
113
|
}
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
return canCreateNodeWithContentInsideAnotherNode([tableCell, tableHeader], convertedFragment);
|
|
124
|
-
}
|
|
125
|
-
if (destParentNodeType === panel) {
|
|
126
|
-
return canCreateNodeWithContentInsideAnotherNode([panel], layoutColumnContent);
|
|
127
|
-
}
|
|
128
|
-
if (destParentNodeType === expand) {
|
|
129
|
-
return canCreateNodeWithContentInsideAnotherNode([expand], layoutColumnContent);
|
|
130
|
-
}
|
|
131
|
-
if (destParentNodeType === nestedExpand) {
|
|
132
|
-
return canCreateNodeWithContentInsideAnotherNode([nestedExpand], layoutColumnContent);
|
|
114
|
+
if (destParentNodeType === tableCell || destParentNodeType === tableHeader) {
|
|
115
|
+
var contentContainsExpand = findChildrenByType(srcNode, expand).length > 0;
|
|
116
|
+
//convert expand to nestedExpand if there are expands inside the layout column
|
|
117
|
+
// otherwise, the createChecked will fail as expand is not a valid child of tableCell/tableHeader, but nestedExpand is
|
|
118
|
+
var convertedFragment = contentContainsExpand ? transformFragmentExpandToNestedExpand(layoutColumnContent) : layoutColumnContent;
|
|
119
|
+
if (!convertedFragment) {
|
|
120
|
+
return false;
|
|
133
121
|
}
|
|
122
|
+
return canCreateNodeWithContentInsideAnotherNode([tableCell, tableHeader], convertedFragment);
|
|
123
|
+
}
|
|
124
|
+
if (destParentNodeType === panel) {
|
|
125
|
+
return canCreateNodeWithContentInsideAnotherNode([panel], layoutColumnContent);
|
|
126
|
+
}
|
|
127
|
+
if (destParentNodeType === expand) {
|
|
128
|
+
return canCreateNodeWithContentInsideAnotherNode([expand], layoutColumnContent);
|
|
129
|
+
}
|
|
130
|
+
if (destParentNodeType === nestedExpand) {
|
|
131
|
+
return canCreateNodeWithContentInsideAnotherNode([nestedExpand], layoutColumnContent);
|
|
134
132
|
}
|
|
135
133
|
}
|
|
136
134
|
|
|
@@ -5,3 +5,12 @@ export declare const getNestedNodePosition: ({ selection, schema, resolve, }: {
|
|
|
5
5
|
schema: Schema;
|
|
6
6
|
selection: Selection;
|
|
7
7
|
}) => number;
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @returns starting position of nested node that drag handle can be shown next to
|
|
11
|
+
*/
|
|
12
|
+
export declare const getNestedNodeStartingPosition: ({ selection, schema, resolve, }: {
|
|
13
|
+
resolve: (pos: number) => ResolvedPos;
|
|
14
|
+
schema: Schema;
|
|
15
|
+
selection: Selection;
|
|
16
|
+
}) => number;
|
|
@@ -5,3 +5,12 @@ export declare const getNestedNodePosition: ({ selection, schema, resolve, }: {
|
|
|
5
5
|
schema: Schema;
|
|
6
6
|
selection: Selection;
|
|
7
7
|
}) => number;
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @returns starting position of nested node that drag handle can be shown next to
|
|
11
|
+
*/
|
|
12
|
+
export declare const getNestedNodeStartingPosition: ({ selection, schema, resolve, }: {
|
|
13
|
+
resolve: (pos: number) => ResolvedPos;
|
|
14
|
+
schema: Schema;
|
|
15
|
+
selection: Selection;
|
|
16
|
+
}) => number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-block-controls",
|
|
3
|
-
"version": "7.2.
|
|
3
|
+
"version": "7.2.9",
|
|
4
4
|
"description": "Block controls plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -126,9 +126,6 @@
|
|
|
126
126
|
"platform_editor_ease_of_use_metrics": {
|
|
127
127
|
"type": "boolean"
|
|
128
128
|
},
|
|
129
|
-
"platform_editor_drag_layout_column_into_nodes": {
|
|
130
|
-
"type": "boolean"
|
|
131
|
-
},
|
|
132
129
|
"platform_editor_elements_dnd_multi_select_patch_2": {
|
|
133
130
|
"type": "boolean"
|
|
134
131
|
},
|