@atlaskit/editor-plugin-block-controls 2.13.2 → 2.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 2.13.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [#157700](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/157700)
8
+ [`83f28893f3406`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/83f28893f3406) -
9
+ ED-25062 implement drop hints
10
+ - Updated dependencies
11
+
12
+ ## 2.13.3
13
+
14
+ ### Patch Changes
15
+
16
+ - [`01ef5296f2ad8`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/01ef5296f2ad8) -
17
+ ED-25331 Fix jittering after dropping blockquotes by setting cursor at inline end pos instead of
18
+ gap cursor
19
+ - Updated dependencies
20
+
3
21
  ## 2.13.2
4
22
 
5
23
  ### Patch Changes
@@ -164,6 +164,7 @@ var dropTargetDecorations = exports.dropTargetDecorations = function dropTargetD
164
164
  (parent === null || parent === void 0 ? void 0 : parent.childCount) < _consts.MAX_LAYOUT_COLUMN_SUPPORTED) {
165
165
  decs.push(createLayoutDropTargetDecoration(pos, {
166
166
  api: api,
167
+ parent: parent,
167
168
  formatMessage: formatMessage
168
169
  }));
169
170
  }
@@ -13,12 +13,14 @@ var _browser = require("@atlaskit/editor-common/browser");
13
13
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
14
14
  var _utils = require("@atlaskit/editor-common/utils");
15
15
  var _state = require("@atlaskit/editor-prosemirror/state");
16
- var _view = require("@atlaskit/editor-prosemirror/view");
16
+ var _view2 = require("@atlaskit/editor-prosemirror/view");
17
17
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
18
18
  var _element = require("@atlaskit/pragmatic-drag-and-drop-auto-scroll/element");
19
19
  var _combine = require("@atlaskit/pragmatic-drag-and-drop/combine");
20
20
  var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
21
21
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
22
+ var _activeAnchorTracker = require("../utils/active-anchor-tracker");
23
+ var _advancedLayoutsFlags = require("../utils/advanced-layouts-flags");
22
24
  var _anchorUtils = require("../utils/anchor-utils");
23
25
  var _dragTargetDebug = require("../utils/drag-target-debug");
24
26
  var _transactions = require("../utils/transactions");
@@ -56,6 +58,9 @@ var destroyFn = function destroyFn(api) {
56
58
  if (isHTMLElement(scrollable)) {
57
59
  scrollable.style.setProperty('scroll-behavior', null);
58
60
  }
61
+ if ((0, _advancedLayoutsFlags.isPreRelease2)()) {
62
+ _activeAnchorTracker.defaultActiveAnchorTracker.reset();
63
+ }
59
64
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref3) {
60
65
  var tr = _ref3.tr;
61
66
  var _ref4 = source.data,
@@ -86,7 +91,7 @@ var destroyFn = function destroyFn(api) {
86
91
  return _combine.combine.apply(void 0, cleanupFn);
87
92
  };
88
93
  var initialState = {
89
- decorations: _view.DecorationSet.empty,
94
+ decorations: _view2.DecorationSet.empty,
90
95
  activeNode: undefined,
91
96
  isDragging: false,
92
97
  isMenuOpen: false,
@@ -135,7 +140,7 @@ var newApply = exports.newApply = function newApply(api, formatMessage, tr, curr
135
140
  var latestActiveNode = (_meta$activeNode = meta === null || meta === void 0 ? void 0 : meta.activeNode) !== null && _meta$activeNode !== void 0 ? _meta$activeNode : activeNode;
136
141
 
137
142
  // Re-create node decorations
138
- var isDecSetEmpty = decorations === _view.DecorationSet.empty;
143
+ var isDecSetEmpty = decorations === _view2.DecorationSet.empty;
139
144
  var isNodeDecsMissing = isDecSetEmpty || maybeNodeCountChanged;
140
145
  var shouldRedrawNodeDecs = !isResizerResizing && isNodeDecsMissing;
141
146
  var isActiveNodeModified = false;
@@ -301,7 +306,7 @@ var oldApply = exports.oldApply = function oldApply(api, formatMessage, tr, curr
301
306
  // (when the table node rerenders)
302
307
  // The activeNode is from the previous rendering cycle, and verify if they share the same anchor.
303
308
  var maybeTableWidthUpdated = (meta === null || meta === void 0 ? void 0 : meta.activeNode) && (meta === null || meta === void 0 || (_meta$activeNode2 = meta.activeNode) === null || _meta$activeNode2 === void 0 ? void 0 : _meta$activeNode2.nodeType) === 'table' && meta.activeNode.anchorName === (activeNode === null || activeNode === void 0 ? void 0 : activeNode.anchorName);
304
- var redrawDecorations = decorations === _view.DecorationSet.empty || (meta === null || meta === void 0 ? void 0 : meta.editorHeight) !== undefined && (meta === null || meta === void 0 ? void 0 : meta.editorHeight) !== editorHeight || (meta === null || meta === void 0 ? void 0 : meta.editorWidthLeft) !== undefined && (meta === null || meta === void 0 ? void 0 : meta.editorWidthLeft) !== editorWidthLeft || (meta === null || meta === void 0 ? void 0 : meta.editorWidthRight) !== undefined && (meta === null || meta === void 0 ? void 0 : meta.editorWidthRight) !== editorWidthRight || maybeWidthUpdated || maybeNodeCountChanged || maybeTableWidthUpdated || resizerMeta === false || isDecsMissing || !!(meta !== null && meta !== void 0 && meta.nodeMoved) && tr.docChanged;
309
+ var redrawDecorations = decorations === _view2.DecorationSet.empty || (meta === null || meta === void 0 ? void 0 : meta.editorHeight) !== undefined && (meta === null || meta === void 0 ? void 0 : meta.editorHeight) !== editorHeight || (meta === null || meta === void 0 ? void 0 : meta.editorWidthLeft) !== undefined && (meta === null || meta === void 0 ? void 0 : meta.editorWidthLeft) !== editorWidthLeft || (meta === null || meta === void 0 ? void 0 : meta.editorWidthRight) !== undefined && (meta === null || meta === void 0 ? void 0 : meta.editorWidthRight) !== editorWidthRight || maybeWidthUpdated || maybeNodeCountChanged || maybeTableWidthUpdated || resizerMeta === false || isDecsMissing || !!(meta !== null && meta !== void 0 && meta.nodeMoved) && tr.docChanged;
305
310
 
306
311
  // Draw node and mouseWrapper decorations at top level node if decorations is empty, editor height changes or node is moved
307
312
  if (redrawDecorations && !isResizerResizing && api) {
@@ -499,6 +504,19 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
499
504
  }
500
505
  return false;
501
506
  },
507
+ dragenter: function dragenter(_view, event) {
508
+ if ((0, _advancedLayoutsFlags.isPreRelease2)()) {
509
+ if (isHTMLElement(event.target)) {
510
+ var closestParentElement = event.target.closest('[data-drag-handler-anchor-depth="0"]');
511
+ if (closestParentElement) {
512
+ var currentAnchor = closestParentElement.getAttribute('data-drag-handler-anchor-name');
513
+ if (currentAnchor) {
514
+ _activeAnchorTracker.defaultActiveAnchorTracker.emit(currentAnchor);
515
+ }
516
+ }
517
+ }
518
+ }
519
+ },
502
520
  dragstart: function dragstart(view) {
503
521
  var _anchorRectCache;
504
522
  (_anchorRectCache = anchorRectCache) === null || _anchorRectCache === void 0 || _anchorRectCache.setEditorView(view);
@@ -11,6 +11,8 @@ var _react2 = require("@emotion/react");
11
11
  var _box = require("@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box");
12
12
  var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
13
13
  var _colors = require("@atlaskit/theme/colors");
14
+ var _decorationsCommon = require("../pm-plugins/decorations-common");
15
+ var _activeAnchorTracker = require("../utils/active-anchor-tracker");
14
16
  var _dragTargetDebug = require("../utils/drag-target-debug");
15
17
  /**
16
18
  * @jsxRuntime classic
@@ -33,17 +35,22 @@ var dropTargetLayoutStyle = (0, _react2.css)({
33
35
  var dropTargetLayoutHintStyle = (0, _react2.css)({
34
36
  height: '100%',
35
37
  position: 'relative',
36
- borderRight: "1px dashed ".concat("var(--ds-background-selected-hovered, ".concat(_colors.B75, ")")),
38
+ borderRight: "1px dashed ".concat("var(--ds-border-focused, ".concat(_colors.B200, ")")),
37
39
  width: 0
38
40
  });
39
41
  var DropTargetLayout = exports.DropTargetLayout = function DropTargetLayout(props) {
40
42
  var api = props.api,
41
- getPos = props.getPos;
43
+ getPos = props.getPos,
44
+ parent = props.parent;
42
45
  var ref = (0, _react.useRef)(null);
43
46
  var _useState = (0, _react.useState)(false),
44
47
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
45
48
  isDraggedOver = _useState2[0],
46
49
  setIsDraggedOver = _useState2[1];
50
+ var anchorName = (0, _decorationsCommon.getNodeAnchor)(parent);
51
+ var _useActiveAnchorTrack = (0, _activeAnchorTracker.useActiveAnchorTracker)(anchorName),
52
+ _useActiveAnchorTrack2 = (0, _slicedToArray2.default)(_useActiveAnchorTrack, 1),
53
+ isActiveAnchor = _useActiveAnchorTrack2[0];
47
54
  var onDrop = (0, _react.useCallback)(function () {
48
55
  var _api$blockControls;
49
56
  var _ref = (api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
@@ -79,7 +86,8 @@ var DropTargetLayout = exports.DropTargetLayout = function DropTargetLayout(prop
79
86
  }, isDraggedOver || (0, _dragTargetDebug.isBlocksDragTargetDebug)() ? (0, _react2.jsx)(_box.DropIndicator, {
80
87
  edge: "right",
81
88
  gap: "-".concat(DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH, "px")
82
- }) : (0, _react2.jsx)("div", {
89
+ }) : isActiveAnchor && (0, _react2.jsx)("div", {
90
+ "data-testid": "block-ctrl-drop-hint",
83
91
  css: dropTargetLayoutHintStyle
84
92
  }));
85
93
  };
@@ -16,6 +16,8 @@ var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
16
16
  var _constants = require("@atlaskit/theme/constants");
17
17
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
18
18
  var _decorationsCommon = require("../pm-plugins/decorations-common");
19
+ var _activeAnchorTracker = require("../utils/active-anchor-tracker");
20
+ var _advancedLayoutsFlags = require("../utils/advanced-layouts-flags");
19
21
  var _anchorUtils = require("../utils/anchor-utils");
20
22
  var _dragTargetDebug = require("../utils/drag-target-debug");
21
23
  var _inlineDropTarget = require("../utils/inline-drop-target");
@@ -71,7 +73,7 @@ var fullHeightStyleAdjustZIndexStyle = (0, _react2.css)({
71
73
  zIndex: 0
72
74
  });
73
75
  var HoverZone = function HoverZone(_ref) {
74
- var onDragEnter = _ref.onDragEnter,
76
+ var _onDragEnter = _ref.onDragEnter,
75
77
  onDragLeave = _ref.onDragLeave,
76
78
  onDrop = _ref.onDrop,
77
79
  node = _ref.node,
@@ -82,19 +84,30 @@ var HoverZone = function HoverZone(_ref) {
82
84
  isNestedDropTarget = _ref.isNestedDropTarget,
83
85
  dropTargetStyle = _ref.dropTargetStyle;
84
86
  var ref = (0, _react.useRef)(null);
87
+ var isRemainingheight = dropTargetStyle === 'remainingHeight';
88
+ var anchorName = (0, _react.useMemo)(function () {
89
+ return node ? (0, _decorationsCommon.getNodeAnchor)(node) : '';
90
+ }, [node]);
91
+ var _useActiveAnchorTrack = (0, _activeAnchorTracker.useActiveAnchorTracker)(anchorName),
92
+ _useActiveAnchorTrack2 = (0, _slicedToArray2.default)(_useActiveAnchorTrack, 2),
93
+ _isActive = _useActiveAnchorTrack2[0],
94
+ setActiveAnchor = _useActiveAnchorTrack2[1];
85
95
  (0, _react.useEffect)(function () {
86
96
  if (ref.current) {
87
97
  return (0, _adapter.dropTargetForElements)({
88
98
  element: ref.current,
89
- onDragEnter: onDragEnter,
99
+ onDragEnter: function onDragEnter() {
100
+ if (!isNestedDropTarget && (0, _advancedLayoutsFlags.isPreRelease2)()) {
101
+ setActiveAnchor();
102
+ }
103
+ _onDragEnter();
104
+ },
90
105
  onDragLeave: onDragLeave,
91
106
  onDrop: onDrop
92
107
  });
93
108
  }
94
- }, [onDragEnter, onDragLeave, onDrop]);
95
- var isRemainingheight = dropTargetStyle === 'remainingHeight';
109
+ }, [isNestedDropTarget, _onDragEnter, onDragLeave, onDrop, setActiveAnchor]);
96
110
  var hoverZoneUpperStyle = (0, _react.useMemo)(function () {
97
- var anchorName = node ? (0, _decorationsCommon.getNodeAnchor)(node) : '';
98
111
  var heightStyleOffset = "var(--editor-block-controls-drop-indicator-gap, 0)/2";
99
112
  var transformOffset = "var(".concat(EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET, ", 0)");
100
113
  var heightStyle = anchorName && enableDropZone.includes((node === null || node === void 0 ? void 0 : node.type.name) || '') ? (0, _anchorUtils.isAnchorSupported)() ? "calc(anchor-size(".concat(anchorName, " height)/2 + ").concat(heightStyleOffset, ")") : "calc(".concat(((anchorRectCache === null || anchorRectCache === void 0 ? void 0 : anchorRectCache.getHeight(anchorName)) || 0) / 2, "px + ").concat(heightStyleOffset, ")") : '4px';
@@ -107,7 +120,7 @@ var HoverZone = function HoverZone(_ref) {
107
120
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
108
121
  maxWidth: "".concat(editorWidth || 0, "px")
109
122
  });
110
- }, [anchorRectCache, editorWidth, node, position]);
123
+ }, [anchorName, anchorRectCache, editorWidth, node === null || node === void 0 ? void 0 : node.type.name, position]);
111
124
 
112
125
  /**
113
126
  * 1. Above the last empty line
@@ -119,15 +132,15 @@ var HoverZone = function HoverZone(_ref) {
119
132
  // only apply upper drop zone
120
133
  if (isRemainingheight && position === 'upper') {
121
134
  // previous node
122
- var anchorName = node ? (0, _decorationsCommon.getNodeAnchor)(node) : '';
135
+ var _anchorName = node ? (0, _decorationsCommon.getNodeAnchor)(node) : '';
123
136
  var top = 'unset';
124
- if (anchorName) {
137
+ if (_anchorName) {
125
138
  var enabledDropZone = enableDropZone.includes((node === null || node === void 0 ? void 0 : node.type.name) || '');
126
139
  if ((0, _anchorUtils.isAnchorSupported)()) {
127
- top = enabledDropZone ? "calc(anchor(".concat(anchorName, " 50%))") : "calc(anchor(".concat(anchorName, " bottom) - 4px)");
140
+ top = enabledDropZone ? "calc(anchor(".concat(_anchorName, " 50%))") : "calc(anchor(".concat(_anchorName, " bottom) - 4px)");
128
141
  } else if (anchorRectCache) {
129
- var preNodeTopPos = anchorRectCache.getTop(anchorName) || 0;
130
- var prevNodeHeight = anchorRectCache.getHeight(anchorName) || 0;
142
+ var preNodeTopPos = anchorRectCache.getTop(_anchorName) || 0;
143
+ var prevNodeHeight = anchorRectCache.getHeight(_anchorName) || 0;
131
144
  top = enabledDropZone ? "calc(".concat(preNodeTopPos, "px + ").concat(prevNodeHeight / 2, "px)") : "calc(".concat(preNodeTopPos, "px + ").concat(prevNodeHeight, "px - 4px)");
132
145
  } else {
133
146
  // Should not happen
@@ -11,7 +11,9 @@ var _react2 = require("@emotion/react");
11
11
  var _hooks = require("@atlaskit/editor-common/hooks");
12
12
  var _box = require("@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box");
13
13
  var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
14
+ var _colors = require("@atlaskit/theme/colors");
14
15
  var _decorationsCommon = require("../pm-plugins/decorations-common");
16
+ var _activeAnchorTracker = require("../utils/active-anchor-tracker");
15
17
  var _anchorUtils = require("../utils/anchor-utils");
16
18
  var _dragTargetDebug = require("../utils/drag-target-debug");
17
19
  /* eslint-disable @atlaskit/design-system/consistent-css-prop-usage */
@@ -38,6 +40,12 @@ var GAP = 4;
38
40
  var HOVER_ZONE_WIDTH_OFFSET = 40;
39
41
  var HOVER_ZONE_HEIGHT_OFFSET = 10;
40
42
  var HOVER_ZONE_DEFAULT_WIDTH = 40;
43
+ var dropTargetLayoutHintStyle = (0, _react2.css)({
44
+ height: '100%',
45
+ position: 'relative',
46
+ borderRight: "1px dashed ".concat("var(--ds-border-focused, ".concat(_colors.B200, ")")),
47
+ width: 0
48
+ });
41
49
  var getDropTargetPositionOverride = function getDropTargetPositionOverride(node, editorWidth) {
42
50
  if (!node || !editorWidth) {
43
51
  return {
@@ -105,6 +113,9 @@ var InlineDropTarget = exports.InlineDropTarget = function InlineDropTarget(_ref
105
113
  isDraggedOver = _useState2[0],
106
114
  setIsDraggedOver = _useState2[1];
107
115
  var anchorName = nextNode ? (0, _decorationsCommon.getNodeAnchor)(nextNode) : '';
116
+ var _useActiveAnchorTrack = (0, _activeAnchorTracker.useActiveAnchorTracker)(anchorName),
117
+ _useActiveAnchorTrack2 = (0, _slicedToArray2.default)(_useActiveAnchorTrack, 1),
118
+ isActiveAnchor = _useActiveAnchorTrack2[0];
108
119
  var handleDragEnter = (0, _react.useCallback)(function () {
109
120
  setIsDraggedOver(true);
110
121
  }, []);
@@ -149,8 +160,11 @@ var InlineDropTarget = exports.InlineDropTarget = function InlineDropTarget(_ref
149
160
  return (0, _react2.jsx)(_react.Fragment, null, (0, _react2.jsx)("div", {
150
161
  "data-test-id": "block-ctrl-drop-target-".concat(position),
151
162
  css: [dropTargetCommonStyle, dropTargetRectStyle]
152
- }, (isDraggedOver || (0, _dragTargetDebug.isBlocksDragTargetDebug)()) && (0, _react2.jsx)(_box.DropIndicator, {
163
+ }, isDraggedOver || (0, _dragTargetDebug.isBlocksDragTargetDebug)() ? (0, _react2.jsx)(_box.DropIndicator, {
153
164
  edge: position
165
+ }) : isActiveAnchor && (0, _react2.jsx)("div", {
166
+ "data-testid": "block-ctrl-drop-hint",
167
+ css: dropTargetLayoutHintStyle
154
168
  })), (0, _react2.jsx)(InlineHoverZone, {
155
169
  position: position,
156
170
  node: nextNode,
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.useActiveAnchorTracker = exports.defaultActiveAnchorTracker = exports.ActiveAnchorTracker = void 0;
8
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
10
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
11
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
12
+ var _events = require("events");
13
+ var _react = require("react");
14
+ var _advancedLayoutsFlags = require("./advanced-layouts-flags");
15
+ var ActiveAnchorTracker = exports.ActiveAnchorTracker = /*#__PURE__*/function () {
16
+ function ActiveAnchorTracker() {
17
+ (0, _classCallCheck2.default)(this, ActiveAnchorTracker);
18
+ (0, _defineProperty2.default)(this, "lastActiveAnchor", '');
19
+ this.emitter = new _events.EventEmitter();
20
+ }
21
+ (0, _createClass2.default)(ActiveAnchorTracker, [{
22
+ key: "subscribe",
23
+ value: function subscribe(anchorName, callback) {
24
+ this.emitter.on(anchorName, callback);
25
+ }
26
+ }, {
27
+ key: "unsubscribe",
28
+ value: function unsubscribe(anchorName, callback) {
29
+ this.emitter.removeListener(anchorName, callback);
30
+ }
31
+ }, {
32
+ key: "emit",
33
+ value: function emit(anchorName) {
34
+ if (this.lastActiveAnchor !== anchorName) {
35
+ this.emitter.emit(this.lastActiveAnchor, false);
36
+ this.emitter.emit(anchorName, true);
37
+ this.lastActiveAnchor = anchorName;
38
+ }
39
+ }
40
+ }, {
41
+ key: "reset",
42
+ value: function reset() {
43
+ this.emitter.removeAllListeners();
44
+ }
45
+ }]);
46
+ return ActiveAnchorTracker;
47
+ }();
48
+ var defaultActiveAnchorTracker = exports.defaultActiveAnchorTracker = new ActiveAnchorTracker();
49
+ var useActiveAnchorTracker = exports.useActiveAnchorTracker = function useActiveAnchorTracker(anchorName) {
50
+ var activeAnchorTracker = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultActiveAnchorTracker;
51
+ var _useState = (0, _react.useState)(false),
52
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
53
+ isActive = _useState2[0],
54
+ setIsActive = _useState2[1];
55
+ var onActive = function onActive(eventIsActive) {
56
+ setIsActive(eventIsActive);
57
+ };
58
+ (0, _react.useEffect)(function () {
59
+ if (activeAnchorTracker && anchorName && (0, _advancedLayoutsFlags.isPreRelease2)()) {
60
+ activeAnchorTracker.subscribe(anchorName, onActive);
61
+ var unsubscribe = function unsubscribe() {
62
+ activeAnchorTracker.unsubscribe(anchorName, onActive);
63
+ };
64
+ return unsubscribe;
65
+ }
66
+ }, [activeAnchorTracker, anchorName]);
67
+ var setActive = (0, _react.useCallback)(function () {
68
+ activeAnchorTracker.emit(anchorName);
69
+ }, [activeAnchorTracker, anchorName]);
70
+ return [isActive, setActive];
71
+ };
@@ -7,6 +7,7 @@ exports.setCursorPositionAtMovedNode = exports.selectNode = exports.getSelection
7
7
  var _selection = require("@atlaskit/editor-common/selection");
8
8
  var _state = require("@atlaskit/editor-prosemirror/state");
9
9
  var _utils = require("@atlaskit/editor-tables/utils");
10
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
10
11
  var getInlineNodePos = exports.getInlineNodePos = function getInlineNodePos(tr, start, nodeSize) {
11
12
  var $startPos = tr.doc.resolve(start);
12
13
  // To trigger the annotation floating toolbar for non-selectable node, we need to select inline nodes
@@ -80,7 +81,8 @@ var setCursorPositionAtMovedNode = exports.setCursorPositionAtMovedNode = functi
80
81
  var nodeSize = node ? node.nodeSize : 1;
81
82
  var selection;
82
83
  // decisionList node is not selectable, but we want to select the whole node not just text
83
- if (isNodeSelection || (node === null || node === void 0 ? void 0 : node.type.name) === 'decisionList') {
84
+ // blockQuote is selectable, but we want to set cursor at the inline end Pos instead of the gap cursor as this causes jittering post drop
85
+ if (isNodeSelection && ((0, _platformFeatureFlags.fg)('platform_editor_element_dnd_nested_fix_patch_4') ? node.type.name !== 'blockquote' : true) || (node === null || node === void 0 ? void 0 : node.type.name) === 'decisionList') {
84
86
  selection = new _selection.GapCursorSelection(tr.doc.resolve(start + node.nodeSize), _selection.Side.RIGHT);
85
87
  } else {
86
88
  var _getInlineNodePos2 = getInlineNodePos(tr, start, nodeSize),
@@ -156,6 +156,7 @@ export const dropTargetDecorations = (newState, api, formatMessage, activeNode,
156
156
  (parent === null || parent === void 0 ? void 0 : parent.childCount) < MAX_LAYOUT_COLUMN_SUPPORTED) {
157
157
  decs.push(createLayoutDropTargetDecoration(pos, {
158
158
  api,
159
+ parent,
159
160
  formatMessage
160
161
  }));
161
162
  }
@@ -11,6 +11,8 @@ 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 { defaultActiveAnchorTracker } from '../utils/active-anchor-tracker';
15
+ import { isPreRelease2 } from '../utils/advanced-layouts-flags';
14
16
  import { AnchorRectCache, isAnchorSupported } from '../utils/anchor-utils';
15
17
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
16
18
  import { getTrMetadata } from '../utils/transactions';
@@ -48,6 +50,9 @@ const destroyFn = api => {
48
50
  if (isHTMLElement(scrollable)) {
49
51
  scrollable.style.setProperty('scroll-behavior', null);
50
52
  }
53
+ if (isPreRelease2()) {
54
+ defaultActiveAnchorTracker.reset();
55
+ }
51
56
  api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
52
57
  tr
53
58
  }) => {
@@ -476,6 +481,19 @@ export const createPlugin = (api, getIntl) => {
476
481
  }
477
482
  return false;
478
483
  },
484
+ dragenter(_view, event) {
485
+ if (isPreRelease2()) {
486
+ if (isHTMLElement(event.target)) {
487
+ const closestParentElement = event.target.closest('[data-drag-handler-anchor-depth="0"]');
488
+ if (closestParentElement) {
489
+ const currentAnchor = closestParentElement.getAttribute('data-drag-handler-anchor-name');
490
+ if (currentAnchor) {
491
+ defaultActiveAnchorTracker.emit(currentAnchor);
492
+ }
493
+ }
494
+ }
495
+ }
496
+ },
479
497
  dragstart(view) {
480
498
  var _anchorRectCache;
481
499
  (_anchorRectCache = anchorRectCache) === null || _anchorRectCache === void 0 ? void 0 : _anchorRectCache.setEditorView(view);
@@ -8,7 +8,9 @@ import { useCallback, useEffect, useRef, useState } from 'react';
8
8
  import { css, jsx } from '@emotion/react';
9
9
  import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box';
10
10
  import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
11
- import { B75 } from '@atlaskit/theme/colors';
11
+ import { B200 } from '@atlaskit/theme/colors';
12
+ import { getNodeAnchor } from '../pm-plugins/decorations-common';
13
+ import { useActiveAnchorTracker } from '../utils/active-anchor-tracker';
12
14
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
13
15
 
14
16
  // 8px gap + 16px on left and right
@@ -25,16 +27,19 @@ const dropTargetLayoutStyle = css({
25
27
  const dropTargetLayoutHintStyle = css({
26
28
  height: '100%',
27
29
  position: 'relative',
28
- borderRight: `1px dashed ${`var(--ds-background-selected-hovered, ${B75})`}`,
30
+ borderRight: `1px dashed ${`var(--ds-border-focused, ${B200})`}`,
29
31
  width: 0
30
32
  });
31
33
  export const DropTargetLayout = props => {
32
34
  const {
33
35
  api,
34
- getPos
36
+ getPos,
37
+ parent
35
38
  } = props;
36
39
  const ref = useRef(null);
37
40
  const [isDraggedOver, setIsDraggedOver] = useState(false);
41
+ const anchorName = getNodeAnchor(parent);
42
+ const [isActiveAnchor] = useActiveAnchorTracker(anchorName);
38
43
  const onDrop = useCallback(() => {
39
44
  var _api$blockControls;
40
45
  const {
@@ -73,7 +78,8 @@ export const DropTargetLayout = props => {
73
78
  }, isDraggedOver || isBlocksDragTargetDebug() ? jsx(DropIndicator, {
74
79
  edge: "right",
75
80
  gap: `-${DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH}px`
76
- }) : jsx("div", {
81
+ }) : isActiveAnchor && jsx("div", {
82
+ "data-testid": "block-ctrl-drop-hint",
77
83
  css: dropTargetLayoutHintStyle
78
84
  }));
79
85
  };
@@ -13,6 +13,8 @@ import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element
13
13
  import { layers } from '@atlaskit/theme/constants';
14
14
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
15
15
  import { getNodeAnchor } from '../pm-plugins/decorations-common';
16
+ import { useActiveAnchorTracker } from '../utils/active-anchor-tracker';
17
+ import { isPreRelease2 } from '../utils/advanced-layouts-flags';
16
18
  import { isAnchorSupported } from '../utils/anchor-utils';
17
19
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
18
20
  import { shouldAllowInlineDropTarget } from '../utils/inline-drop-target';
@@ -73,19 +75,27 @@ const HoverZone = ({
73
75
  dropTargetStyle
74
76
  }) => {
75
77
  const ref = useRef(null);
78
+ const isRemainingheight = dropTargetStyle === 'remainingHeight';
79
+ const anchorName = useMemo(() => {
80
+ return node ? getNodeAnchor(node) : '';
81
+ }, [node]);
82
+ const [_isActive, setActiveAnchor] = useActiveAnchorTracker(anchorName);
76
83
  useEffect(() => {
77
84
  if (ref.current) {
78
85
  return dropTargetForElements({
79
86
  element: ref.current,
80
- onDragEnter,
87
+ onDragEnter: () => {
88
+ if (!isNestedDropTarget && isPreRelease2()) {
89
+ setActiveAnchor();
90
+ }
91
+ onDragEnter();
92
+ },
81
93
  onDragLeave,
82
94
  onDrop
83
95
  });
84
96
  }
85
- }, [onDragEnter, onDragLeave, onDrop]);
86
- const isRemainingheight = dropTargetStyle === 'remainingHeight';
97
+ }, [isNestedDropTarget, onDragEnter, onDragLeave, onDrop, setActiveAnchor]);
87
98
  const hoverZoneUpperStyle = useMemo(() => {
88
- const anchorName = node ? getNodeAnchor(node) : '';
89
99
  const heightStyleOffset = `var(--editor-block-controls-drop-indicator-gap, 0)/2`;
90
100
  const transformOffset = `var(${EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET}, 0)`;
91
101
  const heightStyle = anchorName && enableDropZone.includes((node === null || node === void 0 ? void 0 : node.type.name) || '') ? isAnchorSupported() ? `calc(anchor-size(${anchorName} height)/2 + ${heightStyleOffset})` : `calc(${((anchorRectCache === null || anchorRectCache === void 0 ? void 0 : anchorRectCache.getHeight(anchorName)) || 0) / 2}px + ${heightStyleOffset})` : '4px';
@@ -98,7 +108,7 @@ const HoverZone = ({
98
108
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
99
109
  maxWidth: `${editorWidth || 0}px`
100
110
  });
101
- }, [anchorRectCache, editorWidth, node, position]);
111
+ }, [anchorName, anchorRectCache, editorWidth, node === null || node === void 0 ? void 0 : node.type.name, position]);
102
112
 
103
113
  /**
104
114
  * 1. Above the last empty line
@@ -11,7 +11,9 @@ import { css, jsx } from '@emotion/react';
11
11
  import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
12
12
  import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box';
13
13
  import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
14
+ import { B200 } from '@atlaskit/theme/colors';
14
15
  import { getNodeAnchor } from '../pm-plugins/decorations-common';
16
+ import { useActiveAnchorTracker } from '../utils/active-anchor-tracker';
15
17
  import { isAnchorSupported } from '../utils/anchor-utils';
16
18
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
17
19
  const dropTargetCommonStyle = css({
@@ -29,6 +31,12 @@ const GAP = 4;
29
31
  const HOVER_ZONE_WIDTH_OFFSET = 40;
30
32
  const HOVER_ZONE_HEIGHT_OFFSET = 10;
31
33
  const HOVER_ZONE_DEFAULT_WIDTH = 40;
34
+ const dropTargetLayoutHintStyle = css({
35
+ height: '100%',
36
+ position: 'relative',
37
+ borderRight: `1px dashed ${`var(--ds-border-focused, ${B200})`}`,
38
+ width: 0
39
+ });
32
40
  const getDropTargetPositionOverride = (node, editorWidth) => {
33
41
  if (!node || !editorWidth) {
34
42
  return {
@@ -95,6 +103,7 @@ export const InlineDropTarget = ({
95
103
  } = useSharedPluginState(api, ['width']);
96
104
  const [isDraggedOver, setIsDraggedOver] = useState(false);
97
105
  const anchorName = nextNode ? getNodeAnchor(nextNode) : '';
106
+ const [isActiveAnchor] = useActiveAnchorTracker(anchorName);
98
107
  const handleDragEnter = useCallback(() => {
99
108
  setIsDraggedOver(true);
100
109
  }, []);
@@ -142,8 +151,11 @@ export const InlineDropTarget = ({
142
151
  return jsx(Fragment, null, jsx("div", {
143
152
  "data-test-id": `block-ctrl-drop-target-${position}`,
144
153
  css: [dropTargetCommonStyle, dropTargetRectStyle]
145
- }, (isDraggedOver || isBlocksDragTargetDebug()) && jsx(DropIndicator, {
154
+ }, isDraggedOver || isBlocksDragTargetDebug() ? jsx(DropIndicator, {
146
155
  edge: position
156
+ }) : isActiveAnchor && jsx("div", {
157
+ "data-testid": "block-ctrl-drop-hint",
158
+ css: dropTargetLayoutHintStyle
147
159
  })), jsx(InlineHoverZone, {
148
160
  position: position,
149
161
  node: nextNode,
@@ -0,0 +1,46 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { EventEmitter } from 'events';
3
+ import { useCallback, useEffect, useState } from 'react';
4
+ import { isPreRelease2 } from './advanced-layouts-flags';
5
+ export class ActiveAnchorTracker {
6
+ constructor() {
7
+ _defineProperty(this, "lastActiveAnchor", '');
8
+ this.emitter = new EventEmitter();
9
+ }
10
+ subscribe(anchorName, callback) {
11
+ this.emitter.on(anchorName, callback);
12
+ }
13
+ unsubscribe(anchorName, callback) {
14
+ this.emitter.removeListener(anchorName, callback);
15
+ }
16
+ emit(anchorName) {
17
+ if (this.lastActiveAnchor !== anchorName) {
18
+ this.emitter.emit(this.lastActiveAnchor, false);
19
+ this.emitter.emit(anchorName, true);
20
+ this.lastActiveAnchor = anchorName;
21
+ }
22
+ }
23
+ reset() {
24
+ this.emitter.removeAllListeners();
25
+ }
26
+ }
27
+ export const defaultActiveAnchorTracker = new ActiveAnchorTracker();
28
+ export const useActiveAnchorTracker = (anchorName, activeAnchorTracker = defaultActiveAnchorTracker) => {
29
+ const [isActive, setIsActive] = useState(false);
30
+ const onActive = eventIsActive => {
31
+ setIsActive(eventIsActive);
32
+ };
33
+ useEffect(() => {
34
+ if (activeAnchorTracker && anchorName && isPreRelease2()) {
35
+ activeAnchorTracker.subscribe(anchorName, onActive);
36
+ const unsubscribe = () => {
37
+ activeAnchorTracker.unsubscribe(anchorName, onActive);
38
+ };
39
+ return unsubscribe;
40
+ }
41
+ }, [activeAnchorTracker, anchorName]);
42
+ const setActive = useCallback(() => {
43
+ activeAnchorTracker.emit(anchorName);
44
+ }, [activeAnchorTracker, anchorName]);
45
+ return [isActive, setActive];
46
+ };
@@ -1,6 +1,7 @@
1
1
  import { GapCursorSelection, Side } from '@atlaskit/editor-common/selection';
2
2
  import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
3
3
  import { selectTableClosestToPos } from '@atlaskit/editor-tables/utils';
4
+ import { fg } from '@atlaskit/platform-feature-flags';
4
5
  export const getInlineNodePos = (tr, start, nodeSize) => {
5
6
  const $startPos = tr.doc.resolve(start);
6
7
  // To trigger the annotation floating toolbar for non-selectable node, we need to select inline nodes
@@ -75,7 +76,8 @@ export const setCursorPositionAtMovedNode = (tr, start) => {
75
76
  const nodeSize = node ? node.nodeSize : 1;
76
77
  let selection;
77
78
  // decisionList node is not selectable, but we want to select the whole node not just text
78
- if (isNodeSelection || (node === null || node === void 0 ? void 0 : node.type.name) === 'decisionList') {
79
+ // blockQuote is selectable, but we want to set cursor at the inline end Pos instead of the gap cursor as this causes jittering post drop
80
+ if (isNodeSelection && (fg('platform_editor_element_dnd_nested_fix_patch_4') ? node.type.name !== 'blockquote' : true) || (node === null || node === void 0 ? void 0 : node.type.name) === 'decisionList') {
79
81
  selection = new GapCursorSelection(tr.doc.resolve(start + node.nodeSize), Side.RIGHT);
80
82
  } else {
81
83
  const {
@@ -157,6 +157,7 @@ export var dropTargetDecorations = function dropTargetDecorations(newState, api,
157
157
  (parent === null || parent === void 0 ? void 0 : parent.childCount) < MAX_LAYOUT_COLUMN_SUPPORTED) {
158
158
  decs.push(createLayoutDropTargetDecoration(pos, {
159
159
  api: api,
160
+ parent: parent,
160
161
  formatMessage: formatMessage
161
162
  }));
162
163
  }
@@ -12,6 +12,8 @@ import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-sc
12
12
  import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
13
13
  import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
14
14
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
15
+ import { defaultActiveAnchorTracker } from '../utils/active-anchor-tracker';
16
+ import { isPreRelease2 } from '../utils/advanced-layouts-flags';
15
17
  import { AnchorRectCache, isAnchorSupported } from '../utils/anchor-utils';
16
18
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
17
19
  import { getTrMetadata } from '../utils/transactions';
@@ -49,6 +51,9 @@ var destroyFn = function destroyFn(api) {
49
51
  if (isHTMLElement(scrollable)) {
50
52
  scrollable.style.setProperty('scroll-behavior', null);
51
53
  }
54
+ if (isPreRelease2()) {
55
+ defaultActiveAnchorTracker.reset();
56
+ }
52
57
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref3) {
53
58
  var tr = _ref3.tr;
54
59
  var _ref4 = source.data,
@@ -492,6 +497,19 @@ export var createPlugin = function createPlugin(api, getIntl) {
492
497
  }
493
498
  return false;
494
499
  },
500
+ dragenter: function dragenter(_view, event) {
501
+ if (isPreRelease2()) {
502
+ if (isHTMLElement(event.target)) {
503
+ var closestParentElement = event.target.closest('[data-drag-handler-anchor-depth="0"]');
504
+ if (closestParentElement) {
505
+ var currentAnchor = closestParentElement.getAttribute('data-drag-handler-anchor-name');
506
+ if (currentAnchor) {
507
+ defaultActiveAnchorTracker.emit(currentAnchor);
508
+ }
509
+ }
510
+ }
511
+ }
512
+ },
495
513
  dragstart: function dragstart(view) {
496
514
  var _anchorRectCache;
497
515
  (_anchorRectCache = anchorRectCache) === null || _anchorRectCache === void 0 || _anchorRectCache.setEditorView(view);
@@ -9,7 +9,9 @@ import { useCallback, useEffect, useRef, useState } from 'react';
9
9
  import { css, jsx } from '@emotion/react';
10
10
  import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box';
11
11
  import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
12
- import { B75 } from '@atlaskit/theme/colors';
12
+ import { B200 } from '@atlaskit/theme/colors';
13
+ import { getNodeAnchor } from '../pm-plugins/decorations-common';
14
+ import { useActiveAnchorTracker } from '../utils/active-anchor-tracker';
13
15
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
14
16
 
15
17
  // 8px gap + 16px on left and right
@@ -26,17 +28,22 @@ var dropTargetLayoutStyle = css({
26
28
  var dropTargetLayoutHintStyle = css({
27
29
  height: '100%',
28
30
  position: 'relative',
29
- borderRight: "1px dashed ".concat("var(--ds-background-selected-hovered, ".concat(B75, ")")),
31
+ borderRight: "1px dashed ".concat("var(--ds-border-focused, ".concat(B200, ")")),
30
32
  width: 0
31
33
  });
32
34
  export var DropTargetLayout = function DropTargetLayout(props) {
33
35
  var api = props.api,
34
- getPos = props.getPos;
36
+ getPos = props.getPos,
37
+ parent = props.parent;
35
38
  var ref = useRef(null);
36
39
  var _useState = useState(false),
37
40
  _useState2 = _slicedToArray(_useState, 2),
38
41
  isDraggedOver = _useState2[0],
39
42
  setIsDraggedOver = _useState2[1];
43
+ var anchorName = getNodeAnchor(parent);
44
+ var _useActiveAnchorTrack = useActiveAnchorTracker(anchorName),
45
+ _useActiveAnchorTrack2 = _slicedToArray(_useActiveAnchorTrack, 1),
46
+ isActiveAnchor = _useActiveAnchorTrack2[0];
40
47
  var onDrop = useCallback(function () {
41
48
  var _api$blockControls;
42
49
  var _ref = (api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
@@ -72,7 +79,8 @@ export var DropTargetLayout = function DropTargetLayout(props) {
72
79
  }, isDraggedOver || isBlocksDragTargetDebug() ? jsx(DropIndicator, {
73
80
  edge: "right",
74
81
  gap: "-".concat(DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH, "px")
75
- }) : jsx("div", {
82
+ }) : isActiveAnchor && jsx("div", {
83
+ "data-testid": "block-ctrl-drop-hint",
76
84
  css: dropTargetLayoutHintStyle
77
85
  }));
78
86
  };
@@ -15,6 +15,8 @@ import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element
15
15
  import { layers } from '@atlaskit/theme/constants';
16
16
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
17
17
  import { getNodeAnchor } from '../pm-plugins/decorations-common';
18
+ import { useActiveAnchorTracker } from '../utils/active-anchor-tracker';
19
+ import { isPreRelease2 } from '../utils/advanced-layouts-flags';
18
20
  import { isAnchorSupported } from '../utils/anchor-utils';
19
21
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
20
22
  import { shouldAllowInlineDropTarget } from '../utils/inline-drop-target';
@@ -63,7 +65,7 @@ var fullHeightStyleAdjustZIndexStyle = css({
63
65
  zIndex: 0
64
66
  });
65
67
  var HoverZone = function HoverZone(_ref) {
66
- var onDragEnter = _ref.onDragEnter,
68
+ var _onDragEnter = _ref.onDragEnter,
67
69
  onDragLeave = _ref.onDragLeave,
68
70
  onDrop = _ref.onDrop,
69
71
  node = _ref.node,
@@ -74,19 +76,30 @@ var HoverZone = function HoverZone(_ref) {
74
76
  isNestedDropTarget = _ref.isNestedDropTarget,
75
77
  dropTargetStyle = _ref.dropTargetStyle;
76
78
  var ref = useRef(null);
79
+ var isRemainingheight = dropTargetStyle === 'remainingHeight';
80
+ var anchorName = useMemo(function () {
81
+ return node ? getNodeAnchor(node) : '';
82
+ }, [node]);
83
+ var _useActiveAnchorTrack = useActiveAnchorTracker(anchorName),
84
+ _useActiveAnchorTrack2 = _slicedToArray(_useActiveAnchorTrack, 2),
85
+ _isActive = _useActiveAnchorTrack2[0],
86
+ setActiveAnchor = _useActiveAnchorTrack2[1];
77
87
  useEffect(function () {
78
88
  if (ref.current) {
79
89
  return dropTargetForElements({
80
90
  element: ref.current,
81
- onDragEnter: onDragEnter,
91
+ onDragEnter: function onDragEnter() {
92
+ if (!isNestedDropTarget && isPreRelease2()) {
93
+ setActiveAnchor();
94
+ }
95
+ _onDragEnter();
96
+ },
82
97
  onDragLeave: onDragLeave,
83
98
  onDrop: onDrop
84
99
  });
85
100
  }
86
- }, [onDragEnter, onDragLeave, onDrop]);
87
- var isRemainingheight = dropTargetStyle === 'remainingHeight';
101
+ }, [isNestedDropTarget, _onDragEnter, onDragLeave, onDrop, setActiveAnchor]);
88
102
  var hoverZoneUpperStyle = useMemo(function () {
89
- var anchorName = node ? getNodeAnchor(node) : '';
90
103
  var heightStyleOffset = "var(--editor-block-controls-drop-indicator-gap, 0)/2";
91
104
  var transformOffset = "var(".concat(EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET, ", 0)");
92
105
  var heightStyle = anchorName && enableDropZone.includes((node === null || node === void 0 ? void 0 : node.type.name) || '') ? isAnchorSupported() ? "calc(anchor-size(".concat(anchorName, " height)/2 + ").concat(heightStyleOffset, ")") : "calc(".concat(((anchorRectCache === null || anchorRectCache === void 0 ? void 0 : anchorRectCache.getHeight(anchorName)) || 0) / 2, "px + ").concat(heightStyleOffset, ")") : '4px';
@@ -99,7 +112,7 @@ var HoverZone = function HoverZone(_ref) {
99
112
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
100
113
  maxWidth: "".concat(editorWidth || 0, "px")
101
114
  });
102
- }, [anchorRectCache, editorWidth, node, position]);
115
+ }, [anchorName, anchorRectCache, editorWidth, node === null || node === void 0 ? void 0 : node.type.name, position]);
103
116
 
104
117
  /**
105
118
  * 1. Above the last empty line
@@ -111,15 +124,15 @@ var HoverZone = function HoverZone(_ref) {
111
124
  // only apply upper drop zone
112
125
  if (isRemainingheight && position === 'upper') {
113
126
  // previous node
114
- var anchorName = node ? getNodeAnchor(node) : '';
127
+ var _anchorName = node ? getNodeAnchor(node) : '';
115
128
  var top = 'unset';
116
- if (anchorName) {
129
+ if (_anchorName) {
117
130
  var enabledDropZone = enableDropZone.includes((node === null || node === void 0 ? void 0 : node.type.name) || '');
118
131
  if (isAnchorSupported()) {
119
- top = enabledDropZone ? "calc(anchor(".concat(anchorName, " 50%))") : "calc(anchor(".concat(anchorName, " bottom) - 4px)");
132
+ top = enabledDropZone ? "calc(anchor(".concat(_anchorName, " 50%))") : "calc(anchor(".concat(_anchorName, " bottom) - 4px)");
120
133
  } else if (anchorRectCache) {
121
- var preNodeTopPos = anchorRectCache.getTop(anchorName) || 0;
122
- var prevNodeHeight = anchorRectCache.getHeight(anchorName) || 0;
134
+ var preNodeTopPos = anchorRectCache.getTop(_anchorName) || 0;
135
+ var prevNodeHeight = anchorRectCache.getHeight(_anchorName) || 0;
123
136
  top = enabledDropZone ? "calc(".concat(preNodeTopPos, "px + ").concat(prevNodeHeight / 2, "px)") : "calc(".concat(preNodeTopPos, "px + ").concat(prevNodeHeight, "px - 4px)");
124
137
  } else {
125
138
  // Should not happen
@@ -12,7 +12,9 @@ import { css, jsx } from '@emotion/react';
12
12
  import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
13
13
  import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box';
14
14
  import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
15
+ import { B200 } from '@atlaskit/theme/colors';
15
16
  import { getNodeAnchor } from '../pm-plugins/decorations-common';
17
+ import { useActiveAnchorTracker } from '../utils/active-anchor-tracker';
16
18
  import { isAnchorSupported } from '../utils/anchor-utils';
17
19
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
18
20
  var dropTargetCommonStyle = css({
@@ -30,6 +32,12 @@ var GAP = 4;
30
32
  var HOVER_ZONE_WIDTH_OFFSET = 40;
31
33
  var HOVER_ZONE_HEIGHT_OFFSET = 10;
32
34
  var HOVER_ZONE_DEFAULT_WIDTH = 40;
35
+ var dropTargetLayoutHintStyle = css({
36
+ height: '100%',
37
+ position: 'relative',
38
+ borderRight: "1px dashed ".concat("var(--ds-border-focused, ".concat(B200, ")")),
39
+ width: 0
40
+ });
33
41
  var getDropTargetPositionOverride = function getDropTargetPositionOverride(node, editorWidth) {
34
42
  if (!node || !editorWidth) {
35
43
  return {
@@ -97,6 +105,9 @@ export var InlineDropTarget = function InlineDropTarget(_ref) {
97
105
  isDraggedOver = _useState2[0],
98
106
  setIsDraggedOver = _useState2[1];
99
107
  var anchorName = nextNode ? getNodeAnchor(nextNode) : '';
108
+ var _useActiveAnchorTrack = useActiveAnchorTracker(anchorName),
109
+ _useActiveAnchorTrack2 = _slicedToArray(_useActiveAnchorTrack, 1),
110
+ isActiveAnchor = _useActiveAnchorTrack2[0];
100
111
  var handleDragEnter = useCallback(function () {
101
112
  setIsDraggedOver(true);
102
113
  }, []);
@@ -141,8 +152,11 @@ export var InlineDropTarget = function InlineDropTarget(_ref) {
141
152
  return jsx(Fragment, null, jsx("div", {
142
153
  "data-test-id": "block-ctrl-drop-target-".concat(position),
143
154
  css: [dropTargetCommonStyle, dropTargetRectStyle]
144
- }, (isDraggedOver || isBlocksDragTargetDebug()) && jsx(DropIndicator, {
155
+ }, isDraggedOver || isBlocksDragTargetDebug() ? jsx(DropIndicator, {
145
156
  edge: position
157
+ }) : isActiveAnchor && jsx("div", {
158
+ "data-testid": "block-ctrl-drop-hint",
159
+ css: dropTargetLayoutHintStyle
146
160
  })), jsx(InlineHoverZone, {
147
161
  position: position,
148
162
  node: nextNode,
@@ -0,0 +1,64 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
+ import _createClass from "@babel/runtime/helpers/createClass";
4
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
5
+ import { EventEmitter } from 'events';
6
+ import { useCallback, useEffect, useState } from 'react';
7
+ import { isPreRelease2 } from './advanced-layouts-flags';
8
+ export var ActiveAnchorTracker = /*#__PURE__*/function () {
9
+ function ActiveAnchorTracker() {
10
+ _classCallCheck(this, ActiveAnchorTracker);
11
+ _defineProperty(this, "lastActiveAnchor", '');
12
+ this.emitter = new EventEmitter();
13
+ }
14
+ _createClass(ActiveAnchorTracker, [{
15
+ key: "subscribe",
16
+ value: function subscribe(anchorName, callback) {
17
+ this.emitter.on(anchorName, callback);
18
+ }
19
+ }, {
20
+ key: "unsubscribe",
21
+ value: function unsubscribe(anchorName, callback) {
22
+ this.emitter.removeListener(anchorName, callback);
23
+ }
24
+ }, {
25
+ key: "emit",
26
+ value: function emit(anchorName) {
27
+ if (this.lastActiveAnchor !== anchorName) {
28
+ this.emitter.emit(this.lastActiveAnchor, false);
29
+ this.emitter.emit(anchorName, true);
30
+ this.lastActiveAnchor = anchorName;
31
+ }
32
+ }
33
+ }, {
34
+ key: "reset",
35
+ value: function reset() {
36
+ this.emitter.removeAllListeners();
37
+ }
38
+ }]);
39
+ return ActiveAnchorTracker;
40
+ }();
41
+ export var defaultActiveAnchorTracker = new ActiveAnchorTracker();
42
+ export var useActiveAnchorTracker = function useActiveAnchorTracker(anchorName) {
43
+ var activeAnchorTracker = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultActiveAnchorTracker;
44
+ var _useState = useState(false),
45
+ _useState2 = _slicedToArray(_useState, 2),
46
+ isActive = _useState2[0],
47
+ setIsActive = _useState2[1];
48
+ var onActive = function onActive(eventIsActive) {
49
+ setIsActive(eventIsActive);
50
+ };
51
+ useEffect(function () {
52
+ if (activeAnchorTracker && anchorName && isPreRelease2()) {
53
+ activeAnchorTracker.subscribe(anchorName, onActive);
54
+ var unsubscribe = function unsubscribe() {
55
+ activeAnchorTracker.unsubscribe(anchorName, onActive);
56
+ };
57
+ return unsubscribe;
58
+ }
59
+ }, [activeAnchorTracker, anchorName]);
60
+ var setActive = useCallback(function () {
61
+ activeAnchorTracker.emit(anchorName);
62
+ }, [activeAnchorTracker, anchorName]);
63
+ return [isActive, setActive];
64
+ };
@@ -1,6 +1,7 @@
1
1
  import { GapCursorSelection, Side } from '@atlaskit/editor-common/selection';
2
2
  import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
3
3
  import { selectTableClosestToPos } from '@atlaskit/editor-tables/utils';
4
+ import { fg } from '@atlaskit/platform-feature-flags';
4
5
  export var getInlineNodePos = function getInlineNodePos(tr, start, nodeSize) {
5
6
  var $startPos = tr.doc.resolve(start);
6
7
  // To trigger the annotation floating toolbar for non-selectable node, we need to select inline nodes
@@ -74,7 +75,8 @@ export var setCursorPositionAtMovedNode = function setCursorPositionAtMovedNode(
74
75
  var nodeSize = node ? node.nodeSize : 1;
75
76
  var selection;
76
77
  // decisionList node is not selectable, but we want to select the whole node not just text
77
- if (isNodeSelection || (node === null || node === void 0 ? void 0 : node.type.name) === 'decisionList') {
78
+ // blockQuote is selectable, but we want to set cursor at the inline end Pos instead of the gap cursor as this causes jittering post drop
79
+ if (isNodeSelection && (fg('platform_editor_element_dnd_nested_fix_patch_4') ? node.type.name !== 'blockquote' : true) || (node === null || node === void 0 ? void 0 : node.type.name) === 'decisionList') {
78
80
  selection = new GapCursorSelection(tr.doc.resolve(start + node.nodeSize), Side.RIGHT);
79
81
  } else {
80
82
  var _getInlineNodePos2 = getInlineNodePos(tr, start, nodeSize),
@@ -1,10 +1,12 @@
1
1
  import { jsx } from '@emotion/react';
2
2
  import { type IntlShape } from 'react-intl-next';
3
3
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
4
5
  import type { BlockControlsPlugin } from '../types';
5
6
  export type DropTargetLayoutProps = {
6
7
  api: ExtractInjectionAPI<BlockControlsPlugin> | undefined;
7
8
  getPos: () => number | undefined;
9
+ parent: PMNode;
8
10
  formatMessage?: IntlShape['formatMessage'];
9
11
  };
10
12
  export declare const DropTargetLayout: (props: DropTargetLayoutProps) => jsx.JSX.Element;
@@ -0,0 +1,15 @@
1
+ /// <reference path="../../../../../../typings/events.d.ts" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node/events" />
4
+ import { EventEmitter } from 'events';
5
+ export declare class ActiveAnchorTracker {
6
+ emitter: EventEmitter;
7
+ lastActiveAnchor: string;
8
+ constructor();
9
+ subscribe(anchorName: string, callback: (isActive: boolean) => void): void;
10
+ unsubscribe(anchorName: string, callback: (isActive: boolean) => void): void;
11
+ emit(anchorName: string): void;
12
+ reset(): void;
13
+ }
14
+ export declare const defaultActiveAnchorTracker: ActiveAnchorTracker;
15
+ export declare const useActiveAnchorTracker: (anchorName: string, activeAnchorTracker?: ActiveAnchorTracker) => [boolean, () => void];
@@ -1,10 +1,12 @@
1
1
  import { jsx } from '@emotion/react';
2
2
  import { type IntlShape } from 'react-intl-next';
3
3
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
4
5
  import type { BlockControlsPlugin } from '../types';
5
6
  export type DropTargetLayoutProps = {
6
7
  api: ExtractInjectionAPI<BlockControlsPlugin> | undefined;
7
8
  getPos: () => number | undefined;
9
+ parent: PMNode;
8
10
  formatMessage?: IntlShape['formatMessage'];
9
11
  };
10
12
  export declare const DropTargetLayout: (props: DropTargetLayoutProps) => jsx.JSX.Element;
@@ -0,0 +1,18 @@
1
+ /// <reference path="../../../../../../typings/events.d.ts" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node/events" />
4
+ import { EventEmitter } from 'events';
5
+ export declare class ActiveAnchorTracker {
6
+ emitter: EventEmitter;
7
+ lastActiveAnchor: string;
8
+ constructor();
9
+ subscribe(anchorName: string, callback: (isActive: boolean) => void): void;
10
+ unsubscribe(anchorName: string, callback: (isActive: boolean) => void): void;
11
+ emit(anchorName: string): void;
12
+ reset(): void;
13
+ }
14
+ export declare const defaultActiveAnchorTracker: ActiveAnchorTracker;
15
+ export declare const useActiveAnchorTracker: (anchorName: string, activeAnchorTracker?: ActiveAnchorTracker) => [
16
+ boolean,
17
+ () => void
18
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-controls",
3
- "version": "2.13.2",
3
+ "version": "2.13.4",
4
4
  "description": "Block controls plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@atlaskit/adf-schema": "^44.2.0",
34
- "@atlaskit/editor-common": "^94.9.0",
34
+ "@atlaskit/editor-common": "^94.11.0",
35
35
  "@atlaskit/editor-plugin-accessibility-utils": "^1.2.0",
36
36
  "@atlaskit/editor-plugin-analytics": "^1.10.0",
37
37
  "@atlaskit/editor-plugin-editor-disabled": "^1.3.0",
@@ -39,7 +39,7 @@
39
39
  "@atlaskit/editor-plugin-quick-insert": "^1.6.0",
40
40
  "@atlaskit/editor-plugin-width": "^1.3.0",
41
41
  "@atlaskit/editor-prosemirror": "6.0.0",
42
- "@atlaskit/editor-shared-styles": "^3.1.0",
42
+ "@atlaskit/editor-shared-styles": "^3.2.0",
43
43
  "@atlaskit/editor-tables": "^2.8.0",
44
44
  "@atlaskit/icon": "^22.24.0",
45
45
  "@atlaskit/platform-feature-flags": "^0.3.0",
@@ -49,7 +49,7 @@
49
49
  "@atlaskit/primitives": "^13.0.0",
50
50
  "@atlaskit/theme": "^14.0.0",
51
51
  "@atlaskit/tmp-editor-statsig": "^2.11.0",
52
- "@atlaskit/tokens": "^2.0.0",
52
+ "@atlaskit/tokens": "^2.1.0",
53
53
  "@atlaskit/tooltip": "^18.8.0",
54
54
  "@babel/runtime": "^7.0.0",
55
55
  "@emotion/react": "^11.7.1",
@@ -142,6 +142,9 @@
142
142
  "platform_editor_element_dnd_nested_fix_patch_3": {
143
143
  "type": "boolean"
144
144
  },
145
+ "platform_editor_element_dnd_nested_fix_patch_4": {
146
+ "type": "boolean"
147
+ },
145
148
  "platform_editor_element_dnd_nested_type_error_fix": {
146
149
  "type": "boolean"
147
150
  },