@atlaskit/editor-plugin-block-controls 2.2.1 → 2.3.0
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 +17 -0
- package/dist/cjs/commands/move-node.js +2 -1
- package/dist/cjs/pm-plugins/decorations.js +127 -43
- package/dist/cjs/pm-plugins/main.js +8 -1
- package/dist/cjs/ui/consts.js +3 -3
- package/dist/cjs/ui/drop-target-v2.js +184 -0
- package/dist/cjs/utils/anchor-utils.js +70 -0
- package/dist/cjs/utils/getSelection.js +43 -16
- package/dist/cjs/utils/index.js +12 -0
- package/dist/es2019/commands/move-node.js +2 -1
- package/dist/es2019/pm-plugins/decorations.js +122 -33
- package/dist/es2019/pm-plugins/main.js +8 -1
- package/dist/es2019/ui/consts.js +3 -3
- package/dist/es2019/ui/drop-target-v2.js +171 -0
- package/dist/es2019/utils/anchor-utils.js +51 -0
- package/dist/es2019/utils/getSelection.js +44 -15
- package/dist/es2019/utils/index.js +1 -1
- package/dist/esm/commands/move-node.js +2 -1
- package/dist/esm/pm-plugins/decorations.js +126 -42
- package/dist/esm/pm-plugins/main.js +8 -1
- package/dist/esm/ui/consts.js +3 -3
- package/dist/esm/ui/drop-target-v2.js +176 -0
- package/dist/esm/utils/anchor-utils.js +63 -0
- package/dist/esm/utils/getSelection.js +42 -15
- package/dist/esm/utils/index.js +1 -1
- package/dist/types/pm-plugins/decorations.d.ts +6 -1
- package/dist/types/ui/drop-target-v2.d.ts +8 -0
- package/dist/types/utils/anchor-utils.d.ts +12 -0
- package/dist/types/utils/getSelection.d.ts +5 -0
- package/dist/types/utils/index.d.ts +1 -1
- package/dist/types-ts4.5/pm-plugins/decorations.d.ts +6 -1
- package/dist/types-ts4.5/ui/drop-target-v2.d.ts +8 -0
- package/dist/types-ts4.5/utils/anchor-utils.d.ts +12 -0
- package/dist/types-ts4.5/utils/getSelection.d.ts +5 -0
- package/dist/types-ts4.5/utils/index.d.ts +1 -1
- package/package.json +6 -3
|
@@ -3,9 +3,32 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.selectNode = exports.getSelection = void 0;
|
|
6
|
+
exports.setCursorPositionAtMovedNode = exports.selectNode = exports.getSelection = exports.getInlineNodePos = void 0;
|
|
7
|
+
var _selection = require("@atlaskit/editor-common/selection");
|
|
7
8
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
8
9
|
var _utils = require("@atlaskit/editor-tables/utils");
|
|
10
|
+
var getInlineNodePos = exports.getInlineNodePos = function getInlineNodePos(tr, start, nodeSize) {
|
|
11
|
+
var $startPos = tr.doc.resolve(start);
|
|
12
|
+
// To trigger the annotation floating toolbar for non-selectable node, we need to select inline nodes
|
|
13
|
+
// Find the first inline node in the node
|
|
14
|
+
var inlineNodePos = start;
|
|
15
|
+
var foundInlineNode = false;
|
|
16
|
+
var inlineNodeEndPos = 0;
|
|
17
|
+
tr.doc.nodesBetween($startPos.pos, $startPos.pos + nodeSize, function (n, pos) {
|
|
18
|
+
if (n.isInline) {
|
|
19
|
+
inlineNodeEndPos = pos + n.nodeSize;
|
|
20
|
+
}
|
|
21
|
+
if (n.isInline && !foundInlineNode) {
|
|
22
|
+
inlineNodePos = pos;
|
|
23
|
+
foundInlineNode = true;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
inlineNodePos: inlineNodePos,
|
|
29
|
+
inlineNodeEndPos: inlineNodeEndPos
|
|
30
|
+
};
|
|
31
|
+
};
|
|
9
32
|
var getSelection = exports.getSelection = function getSelection(tr, start) {
|
|
10
33
|
var node = tr.doc.nodeAt(start);
|
|
11
34
|
var isNodeSelection = node && _state.NodeSelection.isSelectable(node);
|
|
@@ -25,21 +48,9 @@ var getSelection = exports.getSelection = function getSelection(tr, start) {
|
|
|
25
48
|
nodeName === 'mediaGroup') {
|
|
26
49
|
return new _state.NodeSelection($startPos);
|
|
27
50
|
} else {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
var foundInlineNode = false;
|
|
32
|
-
var inlineNodeEndPos = 0;
|
|
33
|
-
tr.doc.nodesBetween($startPos.pos, $startPos.pos + nodeSize, function (n, pos) {
|
|
34
|
-
if (n.isInline) {
|
|
35
|
-
inlineNodeEndPos = pos + n.nodeSize;
|
|
36
|
-
}
|
|
37
|
-
if (n.isInline && !foundInlineNode) {
|
|
38
|
-
inlineNodePos = pos;
|
|
39
|
-
foundInlineNode = true;
|
|
40
|
-
}
|
|
41
|
-
return true;
|
|
42
|
-
});
|
|
51
|
+
var _getInlineNodePos = getInlineNodePos(tr, start, nodeSize),
|
|
52
|
+
inlineNodePos = _getInlineNodePos.inlineNodePos,
|
|
53
|
+
inlineNodeEndPos = _getInlineNodePos.inlineNodeEndPos;
|
|
43
54
|
return new _state.TextSelection(tr.doc.resolve(inlineNodeEndPos), tr.doc.resolve(inlineNodePos));
|
|
44
55
|
}
|
|
45
56
|
};
|
|
@@ -51,4 +62,20 @@ var selectNode = exports.selectNode = function selectNode(tr, start, nodeType) {
|
|
|
51
62
|
tr.setSelection(getSelection(tr, start));
|
|
52
63
|
}
|
|
53
64
|
return tr;
|
|
65
|
+
};
|
|
66
|
+
var setCursorPositionAtMovedNode = exports.setCursorPositionAtMovedNode = function setCursorPositionAtMovedNode(tr, start) {
|
|
67
|
+
var node = tr.doc.nodeAt(start);
|
|
68
|
+
var isNodeSelection = node && _state.NodeSelection.isSelectable(node);
|
|
69
|
+
var nodeSize = node ? node.nodeSize : 1;
|
|
70
|
+
var selection;
|
|
71
|
+
// decisionList node is not selectable, but we want to select the whole node not just text
|
|
72
|
+
if (isNodeSelection || (node === null || node === void 0 ? void 0 : node.type.name) === 'decisionList') {
|
|
73
|
+
selection = new _selection.GapCursorSelection(tr.doc.resolve(start + node.nodeSize), _selection.Side.RIGHT);
|
|
74
|
+
} else {
|
|
75
|
+
var _getInlineNodePos2 = getInlineNodePos(tr, start, nodeSize),
|
|
76
|
+
inlineNodeEndPos = _getInlineNodePos2.inlineNodeEndPos;
|
|
77
|
+
selection = new _state.TextSelection(tr.doc.resolve(inlineNodeEndPos));
|
|
78
|
+
}
|
|
79
|
+
tr.setSelection(selection);
|
|
80
|
+
return tr;
|
|
54
81
|
};
|
package/dist/cjs/utils/index.js
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
Object.defineProperty(exports, "getInlineNodePos", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function get() {
|
|
9
|
+
return _getSelection.getInlineNodePos;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
6
12
|
Object.defineProperty(exports, "getNestedNodePosition", {
|
|
7
13
|
enumerable: true,
|
|
8
14
|
get: function get() {
|
|
@@ -21,5 +27,11 @@ Object.defineProperty(exports, "selectNode", {
|
|
|
21
27
|
return _getSelection.selectNode;
|
|
22
28
|
}
|
|
23
29
|
});
|
|
30
|
+
Object.defineProperty(exports, "setCursorPositionAtMovedNode", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function get() {
|
|
33
|
+
return _getSelection.setCursorPositionAtMovedNode;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
24
36
|
var _getSelection = require("./getSelection");
|
|
25
37
|
var _getNestedNodePosition = require("./getNestedNodePosition");
|
|
@@ -10,6 +10,7 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
|
10
10
|
import { DIRECTION } from '../consts';
|
|
11
11
|
import { key } from '../pm-plugins/main';
|
|
12
12
|
import { getNestedNodePosition, selectNode } from '../utils';
|
|
13
|
+
import { setCursorPositionAtMovedNode } from '../utils/getSelection';
|
|
13
14
|
import { canMoveNodeToIndex, isInsideTable, transformSliceExpandToNestedExpand } from '../utils/validation';
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -183,7 +184,7 @@ export const moveNode = api => (start, to, inputMethod = INPUT_METHOD.DRAG_AND_D
|
|
|
183
184
|
mappedTo = tr.mapping.map(to);
|
|
184
185
|
tr.insert(mappedTo, nodeCopy); // insert the content at the new position
|
|
185
186
|
}
|
|
186
|
-
tr = selectNode(tr, mappedTo, node.type.name);
|
|
187
|
+
tr = inputMethod === INPUT_METHOD.DRAG_AND_DROP && fg('platform_editor_element_dnd_nested_fix_patch_2') ? setCursorPositionAtMovedNode(tr, mappedTo) : selectNode(tr, mappedTo, node.type.name);
|
|
187
188
|
tr.setMeta(key, {
|
|
188
189
|
nodeMoved: true
|
|
189
190
|
});
|
|
@@ -8,8 +8,10 @@ import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
|
|
|
8
8
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
9
9
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
10
10
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
11
|
+
import { nodeMargins } from '../ui/consts';
|
|
11
12
|
import { DragHandle } from '../ui/drag-handle';
|
|
12
13
|
import { DropTarget } from '../ui/drop-target';
|
|
14
|
+
import { DropTargetV2, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET } from '../ui/drop-target-v2';
|
|
13
15
|
import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
|
|
14
16
|
import { canMoveNodeToIndex } from '../utils/validation';
|
|
15
17
|
const IGNORE_NODES = ['tableCell', 'tableHeader', 'tableRow', 'layoutColumn', 'listItem', 'caption'];
|
|
@@ -17,24 +19,104 @@ const IGNORE_NODE_DESCENDANTS = ['listItem', 'taskList', 'decisionList', 'mediaS
|
|
|
17
19
|
const PARENT_WITH_END_DROP_TARGET = ['tableCell', 'tableHeader', 'panel', 'layoutColumn', 'expand', 'nestedExpand', 'bodiedExtension'];
|
|
18
20
|
const DISABLE_CHILD_DROP_TARGET = ['orderedList', 'bulletList'];
|
|
19
21
|
const getNestedDepth = () => editorExperiment('nested-dnd', true) ? 100 : 0;
|
|
20
|
-
const
|
|
22
|
+
export const getNodeAnchor = node => {
|
|
23
|
+
const handleId = ObjHash.getForNode(node);
|
|
24
|
+
return `--node-anchor-${node.type.name}-${handleId}`;
|
|
25
|
+
};
|
|
26
|
+
const getNodeMargins = node => {
|
|
27
|
+
if (!node) {
|
|
28
|
+
return nodeMargins['default'];
|
|
29
|
+
}
|
|
30
|
+
const nodeTypeName = node.type.name;
|
|
31
|
+
if (nodeTypeName === 'heading') {
|
|
32
|
+
return nodeMargins[`heading${node.attrs.level}`] || nodeMargins['default'];
|
|
33
|
+
}
|
|
34
|
+
return nodeMargins[nodeTypeName] || nodeMargins['default'];
|
|
35
|
+
};
|
|
36
|
+
const getGapAndOffset = (prevNode, nextNode, parentNode) => {
|
|
37
|
+
if (!prevNode && nextNode) {
|
|
38
|
+
// first node
|
|
39
|
+
return {
|
|
40
|
+
gap: 0,
|
|
41
|
+
offset: 0
|
|
42
|
+
};
|
|
43
|
+
} else if (prevNode && !nextNode) {
|
|
44
|
+
return {
|
|
45
|
+
gap: 0,
|
|
46
|
+
offset: 0
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const top = getNodeMargins(nextNode).top || 4;
|
|
50
|
+
const bottom = getNodeMargins(prevNode).bottom || 4;
|
|
51
|
+
const gap = Math.max(top, bottom);
|
|
52
|
+
let offset = top - gap / 2;
|
|
53
|
+
if ((prevNode === null || prevNode === void 0 ? void 0 : prevNode.type.name) === 'mediaSingle' && (nextNode === null || nextNode === void 0 ? void 0 : nextNode.type.name) === 'mediaSingle') {
|
|
54
|
+
offset = -offset;
|
|
55
|
+
} else if (prevNode !== null && prevNode !== void 0 && prevNode.type.name && ['tableCell', 'tableHeader'].includes(prevNode === null || prevNode === void 0 ? void 0 : prevNode.type.name)) {
|
|
56
|
+
offset = 0;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
gap,
|
|
60
|
+
offset
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
const shouldDescend = node => {
|
|
64
|
+
if (fg('platform_editor_drag_and_drop_target_v2')) {
|
|
65
|
+
return !['mediaSingle', 'paragraph', 'heading'].includes(node.type.name);
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
};
|
|
69
|
+
export const createDropTargetDecoration = (pos, props, side, anchorHeightsCache) => {
|
|
21
70
|
return Decoration.widget(pos, (_, getPos) => {
|
|
22
71
|
const element = document.createElement('div');
|
|
23
72
|
element.setAttribute('data-blocks-drop-target-container', 'true');
|
|
24
73
|
element.style.clear = 'unset';
|
|
25
|
-
|
|
74
|
+
if (fg('platform_editor_drag_and_drop_target_v2')) {
|
|
75
|
+
const {
|
|
76
|
+
gap,
|
|
77
|
+
offset
|
|
78
|
+
} = getGapAndOffset(props.prevNode, props.nextNode, props.parentNode);
|
|
79
|
+
element.style.setProperty(EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET, `${offset}px`);
|
|
80
|
+
element.style.setProperty(EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP, `${gap}px`);
|
|
81
|
+
}
|
|
82
|
+
if (fg('platform_editor_drag_and_drop_target_v2')) {
|
|
83
|
+
ReactDOM.render( /*#__PURE__*/createElement(DropTargetV2, {
|
|
84
|
+
...props,
|
|
85
|
+
getPos,
|
|
86
|
+
anchorHeightsCache
|
|
87
|
+
}), element);
|
|
88
|
+
} else {
|
|
89
|
+
ReactDOM.render( /*#__PURE__*/createElement(DropTarget, {
|
|
90
|
+
...props,
|
|
91
|
+
getPos
|
|
92
|
+
}), element);
|
|
93
|
+
}
|
|
26
94
|
return element;
|
|
27
95
|
}, {
|
|
28
96
|
type: 'drop-target-decoration',
|
|
29
|
-
side
|
|
97
|
+
side
|
|
30
98
|
});
|
|
31
99
|
};
|
|
32
|
-
export const dropTargetDecorations = (newState, api, formatMessage, activeNode) => {
|
|
100
|
+
export const dropTargetDecorations = (newState, api, formatMessage, activeNode, anchorHeightsCache) => {
|
|
33
101
|
const decs = [];
|
|
34
102
|
unmountDecorations('data-blocks-drop-target-container');
|
|
35
103
|
let prevNode;
|
|
36
104
|
const activeNodePos = activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos;
|
|
37
105
|
const activePMNode = typeof activeNodePos === 'number' && newState.doc.resolve(activeNodePos).nodeAfter;
|
|
106
|
+
anchorHeightsCache === null || anchorHeightsCache === void 0 ? void 0 : anchorHeightsCache.clear();
|
|
107
|
+
const prevNodeStack = [];
|
|
108
|
+
const popNodeStack = depth => {
|
|
109
|
+
let result;
|
|
110
|
+
const toDepth = Math.max(depth, 0);
|
|
111
|
+
while (prevNodeStack.length > toDepth) {
|
|
112
|
+
result = prevNodeStack.pop();
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
};
|
|
116
|
+
const pushNodeStack = (node, depth) => {
|
|
117
|
+
popNodeStack(depth);
|
|
118
|
+
prevNodeStack.push(node);
|
|
119
|
+
};
|
|
38
120
|
newState.doc.descendants((node, pos, parent, index) => {
|
|
39
121
|
let depth = 0;
|
|
40
122
|
// drop target deco at the end position
|
|
@@ -42,58 +124,65 @@ export const dropTargetDecorations = (newState, api, formatMessage, activeNode)
|
|
|
42
124
|
if (editorExperiment('nested-dnd', true)) {
|
|
43
125
|
depth = newState.doc.resolve(pos).depth;
|
|
44
126
|
if (node.isInline || !parent || DISABLE_CHILD_DROP_TARGET.includes(parent.type.name)) {
|
|
45
|
-
|
|
127
|
+
if (fg('platform_editor_drag_and_drop_target_v2')) {
|
|
128
|
+
pushNodeStack(node, depth);
|
|
129
|
+
} else {
|
|
130
|
+
prevNode = node;
|
|
131
|
+
}
|
|
46
132
|
return false;
|
|
47
133
|
}
|
|
48
134
|
if (IGNORE_NODES.includes(node.type.name)) {
|
|
49
|
-
|
|
50
|
-
|
|
135
|
+
if (fg('platform_editor_drag_and_drop_target_v2')) {
|
|
136
|
+
pushNodeStack(node, depth);
|
|
137
|
+
} else {
|
|
138
|
+
prevNode = node;
|
|
139
|
+
}
|
|
140
|
+
return shouldDescend(node); //skip over, don't consider it a valid depth
|
|
51
141
|
}
|
|
52
142
|
const canDrop = activePMNode && canMoveNodeToIndex(parent, index, activePMNode);
|
|
53
143
|
|
|
54
144
|
//NOTE: This will block drop targets showing for nodes that are valid after transformation (i.e. expand -> nestedExpand)
|
|
55
145
|
if (!canDrop && !isBlocksDragTargetDebug()) {
|
|
56
|
-
|
|
146
|
+
if (fg('platform_editor_drag_and_drop_target_v2')) {
|
|
147
|
+
pushNodeStack(node, depth);
|
|
148
|
+
} else {
|
|
149
|
+
prevNode = node;
|
|
150
|
+
}
|
|
57
151
|
return false; //not valid pos, so nested not valid either
|
|
58
152
|
}
|
|
59
153
|
if (parent.lastChild === node && !isEmptyParagraph(node) && PARENT_WITH_END_DROP_TARGET.includes(parent.type.name)) {
|
|
60
154
|
endPos = pos + node.nodeSize;
|
|
61
155
|
}
|
|
62
156
|
}
|
|
63
|
-
const previousNode = prevNode; // created scoped variable
|
|
64
|
-
decs.push(createDropTargetDecoration(pos,
|
|
157
|
+
const previousNode = fg('platform_editor_drag_and_drop_target_v2') ? popNodeStack(depth) : prevNode; // created scoped variable
|
|
158
|
+
decs.push(createDropTargetDecoration(pos, {
|
|
65
159
|
api,
|
|
66
|
-
getPos,
|
|
67
160
|
prevNode: previousNode,
|
|
68
161
|
nextNode: node,
|
|
69
|
-
parentNode: parent,
|
|
162
|
+
parentNode: parent || undefined,
|
|
70
163
|
formatMessage
|
|
71
|
-
}))
|
|
164
|
+
}, -1, anchorHeightsCache));
|
|
72
165
|
if (endPos !== undefined) {
|
|
73
|
-
decs.push(createDropTargetDecoration(endPos,
|
|
166
|
+
decs.push(createDropTargetDecoration(endPos, {
|
|
74
167
|
api,
|
|
75
|
-
|
|
76
|
-
parentNode: parent,
|
|
168
|
+
prevNode: fg('platform_editor_drag_and_drop_target_v2') ? node : undefined,
|
|
169
|
+
parentNode: parent || undefined,
|
|
77
170
|
formatMessage
|
|
78
|
-
}))
|
|
171
|
+
}, -1, anchorHeightsCache));
|
|
79
172
|
}
|
|
80
|
-
|
|
81
|
-
|
|
173
|
+
if (fg('platform_editor_drag_and_drop_target_v2')) {
|
|
174
|
+
pushNodeStack(node, depth);
|
|
175
|
+
} else {
|
|
176
|
+
prevNode = node;
|
|
177
|
+
}
|
|
178
|
+
return depth < getNestedDepth() && shouldDescend(node);
|
|
82
179
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
api,
|
|
90
|
-
getPos,
|
|
91
|
-
formatMessage
|
|
92
|
-
}), element);
|
|
93
|
-
return element;
|
|
94
|
-
}, {
|
|
95
|
-
type: 'drop-target-decoration'
|
|
96
|
-
}));
|
|
180
|
+
decs.push(createDropTargetDecoration(newState.doc.nodeSize - 2, {
|
|
181
|
+
api,
|
|
182
|
+
formatMessage,
|
|
183
|
+
prevNode: newState.doc.lastChild || undefined,
|
|
184
|
+
parentNode: newState.doc
|
|
185
|
+
}, undefined, anchorHeightsCache));
|
|
97
186
|
return decs;
|
|
98
187
|
};
|
|
99
188
|
export const emptyParagraphNodeDecorations = () => {
|
|
@@ -11,6 +11,7 @@ import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-sc
|
|
|
11
11
|
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
12
12
|
import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
13
13
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
14
|
+
import { AnchorHeightsCache, isAnchorSupported } from '../utils/anchor-utils';
|
|
14
15
|
import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
|
|
15
16
|
import { dragHandleDecoration, dropTargetDecorations, emptyParagraphNodeDecorations, nodeDecorations } from './decorations';
|
|
16
17
|
import { handleMouseOver } from './handle-mouse-over';
|
|
@@ -97,6 +98,10 @@ export const createPlugin = (api, getIntl) => {
|
|
|
97
98
|
if (fg('platform_editor_element_dnd_nested_fix_patch_2')) {
|
|
98
99
|
// TODO: Remove this once FG is used in code
|
|
99
100
|
}
|
|
101
|
+
let anchorHeightsCache;
|
|
102
|
+
if (!isAnchorSupported() && fg('platform_editor_drag_and_drop_target_v2')) {
|
|
103
|
+
anchorHeightsCache = new AnchorHeightsCache();
|
|
104
|
+
}
|
|
100
105
|
return new SafePlugin({
|
|
101
106
|
key,
|
|
102
107
|
state: {
|
|
@@ -244,7 +249,7 @@ export const createPlugin = (api, getIntl) => {
|
|
|
244
249
|
// if the transaction is only for analytics and user is dragging, continue to draw drop targets
|
|
245
250
|
if (shouldCreateDropTargets || isBlocksDragTargetDebug()) {
|
|
246
251
|
var _meta$activeNode6;
|
|
247
|
-
const decs = dropTargetDecorations(newState, api, formatMessage, isNestedEnabled ? (_meta$activeNode6 = meta === null || meta === void 0 ? void 0 : meta.activeNode) !== null && _meta$activeNode6 !== void 0 ? _meta$activeNode6 : mappedActiveNodePos : meta === null || meta === void 0 ? void 0 : meta.activeNode);
|
|
252
|
+
const decs = dropTargetDecorations(newState, api, formatMessage, isNestedEnabled ? (_meta$activeNode6 = meta === null || meta === void 0 ? void 0 : meta.activeNode) !== null && _meta$activeNode6 !== void 0 ? _meta$activeNode6 : mappedActiveNodePos : meta === null || meta === void 0 ? void 0 : meta.activeNode, anchorHeightsCache);
|
|
248
253
|
decorations = decorations.add(newState.doc, decs);
|
|
249
254
|
}
|
|
250
255
|
}
|
|
@@ -319,6 +324,8 @@ export const createPlugin = (api, getIntl) => {
|
|
|
319
324
|
return false;
|
|
320
325
|
},
|
|
321
326
|
dragstart(view) {
|
|
327
|
+
var _anchorHeightsCache;
|
|
328
|
+
(_anchorHeightsCache = anchorHeightsCache) === null || _anchorHeightsCache === void 0 ? void 0 : _anchorHeightsCache.setEditorView(view);
|
|
322
329
|
view.dispatch(view.state.tr.setMeta(key, {
|
|
323
330
|
isPMDragging: true
|
|
324
331
|
}));
|
package/dist/es2019/ui/consts.js
CHANGED
|
@@ -116,7 +116,7 @@ export const nodeMargins = {
|
|
|
116
116
|
bottom: 0
|
|
117
117
|
},
|
|
118
118
|
codeBlock: {
|
|
119
|
-
top:
|
|
119
|
+
top: 12,
|
|
120
120
|
bottom: 0
|
|
121
121
|
},
|
|
122
122
|
panel: {
|
|
@@ -124,8 +124,8 @@ export const nodeMargins = {
|
|
|
124
124
|
bottom: 0
|
|
125
125
|
},
|
|
126
126
|
rule: {
|
|
127
|
-
top:
|
|
128
|
-
bottom:
|
|
127
|
+
top: 24,
|
|
128
|
+
bottom: 24
|
|
129
129
|
},
|
|
130
130
|
mediaSingle: {
|
|
131
131
|
top: 24,
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jsxRuntime classic
|
|
3
|
+
* @jsx jsx
|
|
4
|
+
*/
|
|
5
|
+
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
8
|
+
import { css, jsx } from '@emotion/react';
|
|
9
|
+
import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
|
|
10
|
+
import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box';
|
|
11
|
+
import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
12
|
+
import { layers } from '@atlaskit/theme/constants';
|
|
13
|
+
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
14
|
+
import { getNodeAnchor } from '../pm-plugins/decorations';
|
|
15
|
+
import { isAnchorSupported } from '../utils/anchor-utils';
|
|
16
|
+
import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
|
|
17
|
+
import { getNestedNodeLeftPaddingMargin } from './consts';
|
|
18
|
+
const DEFAULT_DROP_INDICATOR_WIDTH = 760;
|
|
19
|
+
const EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_WIDTH = '--editor-block-controls-drop-indicator-width';
|
|
20
|
+
const EDITOR_BLOCK_CONTROLS_DROP_TARGET_LEFT_MARGIN = '--editor-block-controls-drop-target-leftMargin';
|
|
21
|
+
const EDITOR_BLOCK_CONTROLS_DROP_TARGET_ZINDEX = '--editor-block-controls-drop-target-zindex';
|
|
22
|
+
export const EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET = '--editor-block-controls-drop-indicator-offset';
|
|
23
|
+
export const EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP = '--editor-block-controls-drop-indicator-gap';
|
|
24
|
+
const styleDropTarget = css({
|
|
25
|
+
marginLeft: `calc(-1 * var(${EDITOR_BLOCK_CONTROLS_DROP_TARGET_LEFT_MARGIN}, 0))`,
|
|
26
|
+
paddingLeft: `var(${EDITOR_BLOCK_CONTROLS_DROP_TARGET_LEFT_MARGIN}, 0)`,
|
|
27
|
+
position: 'absolute',
|
|
28
|
+
left: '0',
|
|
29
|
+
display: 'block',
|
|
30
|
+
zIndex: `var(${EDITOR_BLOCK_CONTROLS_DROP_TARGET_ZINDEX}, 110)`,
|
|
31
|
+
transform: `translateY(var(${EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET}, 0))`
|
|
32
|
+
});
|
|
33
|
+
const styleDropIndicator = css({
|
|
34
|
+
height: '100%',
|
|
35
|
+
margin: '0 auto',
|
|
36
|
+
position: 'relative',
|
|
37
|
+
width: `var(${EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_WIDTH}, 100%)`
|
|
38
|
+
});
|
|
39
|
+
const nestedDropIndicatorStyle = css({
|
|
40
|
+
position: 'relative'
|
|
41
|
+
});
|
|
42
|
+
const dropZoneStyles = css({
|
|
43
|
+
margin: 0,
|
|
44
|
+
position: 'absolute',
|
|
45
|
+
width: '100%',
|
|
46
|
+
zIndex: 110,
|
|
47
|
+
minHeight: '4px'
|
|
48
|
+
});
|
|
49
|
+
const nestedDropZoneStyle = css({
|
|
50
|
+
left: '4px',
|
|
51
|
+
right: '4px',
|
|
52
|
+
width: 'unset'
|
|
53
|
+
});
|
|
54
|
+
const enableDropZone = ['paragraph', 'mediaSingle', 'heading', 'codeBlock', 'decisionList', 'bulletList', 'orderedList', 'taskList', 'extension', 'blockCard'];
|
|
55
|
+
const HoverZone = ({
|
|
56
|
+
onDragEnter,
|
|
57
|
+
onDragLeave,
|
|
58
|
+
onDrop,
|
|
59
|
+
node,
|
|
60
|
+
editorWidth,
|
|
61
|
+
anchorHeightsCache,
|
|
62
|
+
position,
|
|
63
|
+
isNestedDropTarget
|
|
64
|
+
}) => {
|
|
65
|
+
const ref = useRef(null);
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (ref.current) {
|
|
68
|
+
return dropTargetForElements({
|
|
69
|
+
element: ref.current,
|
|
70
|
+
onDragEnter,
|
|
71
|
+
onDragLeave,
|
|
72
|
+
onDrop
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}, [onDragEnter, onDragLeave, onDrop]);
|
|
76
|
+
const hoverZoneUpperStyle = useMemo(() => {
|
|
77
|
+
const anchorName = node ? getNodeAnchor(node) : '';
|
|
78
|
+
const heightStyleOffset = `var(--editor-block-controls-drop-indicator-gap, 0)/2`;
|
|
79
|
+
const transformOffset = `var(${EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET}, 0)`;
|
|
80
|
+
const heightStyle = anchorName && enableDropZone.includes((node === null || node === void 0 ? void 0 : node.type.name) || '') ? isAnchorSupported() ? `calc(anchor-size(${anchorName} height)/2 + ${heightStyleOffset})` : `calc(${((anchorHeightsCache === null || anchorHeightsCache === void 0 ? void 0 : anchorHeightsCache.getHeight(anchorName)) || 0) / 2}px + ${heightStyleOffset})` : '4px';
|
|
81
|
+
const transform = position === 'upper' ? `translateY(calc(-100% + ${transformOffset}))` : `translateY(${transformOffset})`;
|
|
82
|
+
return css({
|
|
83
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
|
|
84
|
+
height: heightStyle,
|
|
85
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
|
|
86
|
+
transform: transform,
|
|
87
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
|
|
88
|
+
maxWidth: `${editorWidth || 0}px`
|
|
89
|
+
});
|
|
90
|
+
}, [anchorHeightsCache, editorWidth, node, position]);
|
|
91
|
+
return jsx("div", {
|
|
92
|
+
ref: ref
|
|
93
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
|
|
94
|
+
,
|
|
95
|
+
className: `drop-target-hover-zone-${position}`
|
|
96
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
97
|
+
,
|
|
98
|
+
css: [dropZoneStyles, isNestedDropTarget && nestedDropZoneStyle, hoverZoneUpperStyle]
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
export const DropTargetV2 = ({
|
|
102
|
+
api,
|
|
103
|
+
getPos,
|
|
104
|
+
prevNode,
|
|
105
|
+
nextNode,
|
|
106
|
+
parentNode,
|
|
107
|
+
formatMessage,
|
|
108
|
+
anchorHeightsCache
|
|
109
|
+
}) => {
|
|
110
|
+
const [isDraggedOver, setIsDraggedOver] = useState(false);
|
|
111
|
+
const {
|
|
112
|
+
widthState
|
|
113
|
+
} = useSharedPluginState(api, ['width']);
|
|
114
|
+
const isNestedDropTarget = (parentNode === null || parentNode === void 0 ? void 0 : parentNode.type.name) !== 'doc';
|
|
115
|
+
const onDrop = () => {
|
|
116
|
+
var _api$blockControls;
|
|
117
|
+
const {
|
|
118
|
+
activeNode
|
|
119
|
+
} = (api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {};
|
|
120
|
+
if (!activeNode) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const pos = getPos();
|
|
124
|
+
if (activeNode && pos !== undefined) {
|
|
125
|
+
var _api$core, _api$blockControls2, _api$blockControls2$c;
|
|
126
|
+
const {
|
|
127
|
+
pos: start
|
|
128
|
+
} = activeNode;
|
|
129
|
+
api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : (_api$blockControls2$c = _api$blockControls2.commands) === null || _api$blockControls2$c === void 0 ? void 0 : _api$blockControls2$c.moveNode(start, pos, undefined, formatMessage));
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const dynamicStyle = {
|
|
133
|
+
width: isNestedDropTarget ? 'unset' : '100%',
|
|
134
|
+
[EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_WIDTH]: isNestedDropTarget ? '100%' : `${(widthState === null || widthState === void 0 ? void 0 : widthState.lineLength) || DEFAULT_DROP_INDICATOR_WIDTH}px`,
|
|
135
|
+
[EDITOR_BLOCK_CONTROLS_DROP_TARGET_LEFT_MARGIN]: isNestedDropTarget ? getNestedNodeLeftPaddingMargin(parentNode === null || parentNode === void 0 ? void 0 : parentNode.type.name) : '0',
|
|
136
|
+
[EDITOR_BLOCK_CONTROLS_DROP_TARGET_ZINDEX]: editorExperiment('nested-dnd', true) ? layers.navigation() : layers.card()
|
|
137
|
+
};
|
|
138
|
+
return jsx(Fragment, null, jsx(HoverZone, {
|
|
139
|
+
onDragEnter: () => setIsDraggedOver(true),
|
|
140
|
+
onDragLeave: () => setIsDraggedOver(false),
|
|
141
|
+
onDrop: onDrop,
|
|
142
|
+
node: prevNode,
|
|
143
|
+
editorWidth: widthState === null || widthState === void 0 ? void 0 : widthState.lineLength,
|
|
144
|
+
anchorHeightsCache: anchorHeightsCache,
|
|
145
|
+
position: "upper",
|
|
146
|
+
isNestedDropTarget: isNestedDropTarget
|
|
147
|
+
}), jsx("div", {
|
|
148
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
149
|
+
css: [styleDropTarget, isNestedDropTarget && nestedDropIndicatorStyle]
|
|
150
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
|
|
151
|
+
,
|
|
152
|
+
style: dynamicStyle,
|
|
153
|
+
"data-testid": "block-ctrl-drop-target"
|
|
154
|
+
},
|
|
155
|
+
// 4px gap to clear expand node border
|
|
156
|
+
(isDraggedOver || isBlocksDragTargetDebug()) && jsx("div", {
|
|
157
|
+
css: styleDropIndicator,
|
|
158
|
+
"data-testid": "block-ctrl-drop-indicator"
|
|
159
|
+
}, jsx(DropIndicator, {
|
|
160
|
+
edge: "bottom"
|
|
161
|
+
}))), jsx(HoverZone, {
|
|
162
|
+
onDragEnter: () => setIsDraggedOver(true),
|
|
163
|
+
onDragLeave: () => setIsDraggedOver(false),
|
|
164
|
+
onDrop: onDrop,
|
|
165
|
+
node: nextNode,
|
|
166
|
+
editorWidth: widthState === null || widthState === void 0 ? void 0 : widthState.lineLength,
|
|
167
|
+
anchorHeightsCache: anchorHeightsCache,
|
|
168
|
+
position: "lower",
|
|
169
|
+
isNestedDropTarget: isNestedDropTarget
|
|
170
|
+
}));
|
|
171
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import memoizeOne from 'memoize-one';
|
|
3
|
+
export const isAnchorSupported = memoizeOne(() => {
|
|
4
|
+
// directly use CSS would cause failed SSR tests.
|
|
5
|
+
if (window.CSS && window.CSS.supports) {
|
|
6
|
+
return window.CSS.supports('anchor-name: --a');
|
|
7
|
+
}
|
|
8
|
+
return false;
|
|
9
|
+
});
|
|
10
|
+
export class AnchorHeightsCache {
|
|
11
|
+
constructor() {
|
|
12
|
+
_defineProperty(this, "anchorHeightsMap", {});
|
|
13
|
+
_defineProperty(this, "isAnchorSupported", isAnchorSupported());
|
|
14
|
+
_defineProperty(this, "isDirty", true);
|
|
15
|
+
_defineProperty(this, "view", null);
|
|
16
|
+
}
|
|
17
|
+
clear() {
|
|
18
|
+
this.isDirty = true;
|
|
19
|
+
this.anchorHeightsMap = {};
|
|
20
|
+
}
|
|
21
|
+
getHeights() {
|
|
22
|
+
if (this.isDirty) {
|
|
23
|
+
var _this$view;
|
|
24
|
+
const anchorElements = ((_this$view = this.view) === null || _this$view === void 0 ? void 0 : _this$view.dom.querySelectorAll('[data-drag-handler-anchor-name]')) || [];
|
|
25
|
+
this.anchorHeightsMap = Array.from(anchorElements).reduce((prev, curr) => {
|
|
26
|
+
const anchorName = curr.getAttribute('data-drag-handler-anchor-name');
|
|
27
|
+
if (anchorName) {
|
|
28
|
+
return {
|
|
29
|
+
...prev,
|
|
30
|
+
[anchorName]: curr.clientHeight
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return prev;
|
|
34
|
+
}, {});
|
|
35
|
+
this.isDirty = false;
|
|
36
|
+
}
|
|
37
|
+
return this.anchorHeightsMap;
|
|
38
|
+
}
|
|
39
|
+
setEditorView(view) {
|
|
40
|
+
if (this.view !== view) {
|
|
41
|
+
this.view = view;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
getHeight(anchorName) {
|
|
45
|
+
if (this.isAnchorSupported) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const heights = this.getHeights();
|
|
49
|
+
return heights[anchorName];
|
|
50
|
+
}
|
|
51
|
+
}
|