@atlaskit/editor-plugin-block-controls 1.4.21 → 1.4.23

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,21 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 1.4.23
4
+
5
+ ### Patch Changes
6
+
7
+ - [#112385](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/112385)
8
+ [`7889fc5a6eff5`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/7889fc5a6eff5) -
9
+ Add new moved events for dnd, change which events are fired in block control plugin
10
+
11
+ ## 1.4.22
12
+
13
+ ### Patch Changes
14
+
15
+ - [#111855](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/111855)
16
+ [`858997cc1d1e0`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/858997cc1d1e0) -
17
+ ED-23619 Improve drop latency by cleaning up decorations before they are being redrawn
18
+
3
19
  ## 1.4.21
4
20
 
5
21
  ### Patch Changes
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.blockControlsPlugin = void 0;
8
8
  var _react = _interopRequireDefault(require("react"));
9
+ var _analytics = require("@atlaskit/editor-common/analytics");
9
10
  var _main = require("./pm-plugins/main");
10
11
  var _dragHandleMenu = require("./ui/drag-handle-menu");
11
12
  var _globalStyles = require("./ui/global-styles");
@@ -25,9 +26,10 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
25
26
  commands: {
26
27
  moveNode: function moveNode(start, to) {
27
28
  return function (_ref2) {
28
- var _node$nodeSize;
29
+ var _node$nodeSize, _api$analytics;
29
30
  var tr = _ref2.tr;
30
31
  var node = tr.doc.nodeAt(start);
32
+ var resolvedNode = tr.doc.resolve(start);
31
33
  if (!node) {
32
34
  return tr;
33
35
  }
@@ -42,6 +44,16 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
42
44
  nodeMoved: true
43
45
  });
44
46
  api === null || api === void 0 || api.core.actions.focus();
47
+ api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
48
+ eventType: _analytics.EVENT_TYPE.TRACK,
49
+ action: _analytics.ACTION.MOVED,
50
+ actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
51
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
52
+ attributes: {
53
+ nodeDepth: resolvedNode.depth,
54
+ nodeType: node.type.name
55
+ }
56
+ })(tr);
45
57
  return tr;
46
58
  };
47
59
  },
@@ -14,6 +14,7 @@ var _dropTarget = require("../ui/drop-target");
14
14
  var _mouseMoveWrapper = require("../ui/mouse-move-wrapper");
15
15
  var dropTargetDecorations = exports.dropTargetDecorations = function dropTargetDecorations(oldState, newState, api) {
16
16
  var decs = [];
17
+ unmountDecorations('data-blocks-drop-target-container');
17
18
  // Decoration state is used to keep track of the position of the drop targets
18
19
  // and allows us to easily map the updated position in the plugin apply method.
19
20
  var decorationState = [];
@@ -24,6 +25,7 @@ var dropTargetDecorations = exports.dropTargetDecorations = function dropTargetD
24
25
  });
25
26
  decs.push(_view.Decoration.widget(pos, function () {
26
27
  var element = document.createElement('div');
28
+ element.setAttribute('data-blocks-drop-target-container', 'true');
27
29
  _reactDom.default.render( /*#__PURE__*/(0, _react.createElement)(_dropTarget.DropTarget, {
28
30
  api: api,
29
31
  index: index
@@ -48,6 +50,7 @@ var dropTargetDecorations = exports.dropTargetDecorations = function dropTargetD
48
50
  });
49
51
  decs.push(_view.Decoration.widget(newState.doc.nodeSize - 2, function () {
50
52
  var element = document.createElement('div');
53
+ element.setAttribute('data-blocks-drop-target-container', 'true');
51
54
  _reactDom.default.render( /*#__PURE__*/(0, _react.createElement)(_dropTarget.DropTarget, {
52
55
  api: api,
53
56
  index: decorationState.length
@@ -80,10 +83,12 @@ var nodeDecorations = exports.nodeDecorations = function nodeDecorations(newStat
80
83
  */
81
84
  var mouseMoveWrapperDecorations = exports.mouseMoveWrapperDecorations = function mouseMoveWrapperDecorations(newState, api) {
82
85
  var decs = [];
86
+ unmountDecorations('data-blocks-decoration-container');
83
87
  newState.doc.descendants(function (node, pos, _parent, index) {
84
88
  var anchorName = "--node-anchor-".concat(node.type.name, "-").concat(index);
85
89
  decs.push(_view.Decoration.widget(pos, function (view, getPos) {
86
90
  var element = document.createElement('div');
91
+ element.setAttribute('data-blocks-decoration-container', 'true');
87
92
  _reactDom.default.render( /*#__PURE__*/(0, _react.createElement)(_mouseMoveWrapper.MouseMoveWrapper, {
88
93
  view: view,
89
94
  api: api,
@@ -108,6 +113,7 @@ var dragHandleDecoration = exports.dragHandleDecoration = function dragHandleDec
108
113
  return _view.Decoration.widget(pos, function (view, getPos) {
109
114
  var element = document.createElement('div');
110
115
  element.setAttribute('data-testid', 'block-ctrl-decorator-widget');
116
+ element.setAttribute('data-blocks-drag-handle-container', 'true');
111
117
  _reactDom.default.render( /*#__PURE__*/(0, _react.createElement)(_dragHandle.DragHandle, {
112
118
  view: view,
113
119
  api: api,
@@ -118,6 +124,17 @@ var dragHandleDecoration = exports.dragHandleDecoration = function dragHandleDec
118
124
  return element;
119
125
  }, {
120
126
  side: -1,
121
- id: 'drag-handle'
127
+ id: 'drag-handle',
128
+ destroy: function destroy(node) {
129
+ _reactDom.default.unmountComponentAtNode(node);
130
+ }
131
+ });
132
+ };
133
+ var unmountDecorations = function unmountDecorations(selector) {
134
+ // Removing decorations manually instead of using native destroy function in prosemirror API
135
+ // as it was more responsive and causes less re-rendering
136
+ var decorationsToRemove = document.querySelectorAll("[".concat(selector, "=\"true\"]"));
137
+ decorationsToRemove.forEach(function (el) {
138
+ _reactDom.default.unmountComponentAtNode(el);
122
139
  });
123
140
  };
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.key = exports.createPlugin = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
9
  var _rafSchd = _interopRequireDefault(require("raf-schd"));
10
+ var _steps = require("@atlaskit/adf-schema/steps");
10
11
  var _analytics = require("@atlaskit/editor-common/analytics");
11
12
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
12
13
  var _state = require("@atlaskit/editor-prosemirror/state");
@@ -34,18 +35,17 @@ var destroyFn = function destroyFn(api) {
34
35
  scrollable.style.setProperty('scroll-behavior', 'unset');
35
36
  },
36
37
  onDrop: function onDrop(_ref2) {
38
+ var _api$core;
37
39
  var location = _ref2.location,
38
40
  source = _ref2.source;
39
41
  scrollable.style.setProperty('scroll-behavior', null);
40
-
41
- // if no drop targets are rendered, assume that drop is invalid
42
- if (location.current.dropTargets.length === 0) {
43
- var _api$core;
44
- var _ref3 = source.data,
45
- start = _ref3.start;
46
- api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref4) {
42
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref3) {
43
+ var tr = _ref3.tr;
44
+ var _ref4 = source.data,
45
+ start = _ref4.start;
46
+ // if no drop targets are rendered, assume that drop is invalid
47
+ if (location.current.dropTargets.length === 0) {
47
48
  var _api$analytics;
48
- var tr = _ref4.tr;
49
49
  var resolvedMovingNode = tr.doc.resolve(start);
50
50
  var maybeNode = resolvedMovingNode.nodeAfter;
51
51
  api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
@@ -58,9 +58,11 @@ var destroyFn = function destroyFn(api) {
58
58
  nodeType: (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name) || ''
59
59
  }
60
60
  })(tr);
61
- return tr;
61
+ }
62
+ return tr.setMeta(key, {
63
+ isDragging: false
62
64
  });
63
- }
65
+ });
64
66
  }
65
67
  }));
66
68
  return _combine.combine.apply(void 0, cleanupFn);
@@ -87,7 +89,7 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
87
89
  return initialState;
88
90
  },
89
91
  apply: function apply(tr, currentState, oldState, newState) {
90
- var _decorationState, _meta$activeNode, _meta$isDragging, _meta$editorHeight;
92
+ var _meta$activeNode, _meta$isDragging, _meta$editorHeight;
91
93
  if (initialState.isDocSizeLimitEnabled && newState.doc.nodeSize > DRAG_AND_DROP_DOC_SIZE_LIMIT) {
92
94
  return initialState;
93
95
  }
@@ -96,8 +98,14 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
96
98
  isMenuOpen = currentState.isMenuOpen,
97
99
  decorationState = currentState.decorationState,
98
100
  editorHeight = currentState.editorHeight,
99
- isResizerResizing = currentState.isResizerResizing;
101
+ isResizerResizing = currentState.isResizerResizing,
102
+ isDragging = currentState.isDragging;
100
103
  var meta = tr.getMeta(key);
104
+ // when creating analytics during drag/drop events, PM thinks the doc has changed
105
+ // so tr.docChange is true and causes some decorations to not render
106
+ var isAnalyticTr = tr.steps.every(function (step) {
107
+ return step instanceof _steps.AnalyticsStep;
108
+ });
101
109
 
102
110
  // If tables or media are being resized, we want to hide the drag handle
103
111
  var resizerMeta = tr.getMeta('is-resizer-resizing');
@@ -127,7 +135,14 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
127
135
  // Note: Quite often the handle is not in the right position after a node is moved
128
136
  // it is safer for now to not show it when a node is moved
129
137
  if (activeNode && !(meta !== null && meta !== void 0 && meta.nodeMoved)) {
130
- var draghandleDec = (0, _decorations.dragHandleDecoration)(activeNode.pos, activeNode.anchorName, activeNode.nodeType, api);
138
+ var newActiveNode = activeNode && tr.doc.nodeAt(tr.mapping.map(activeNode.pos));
139
+ var nodeType = activeNode.nodeType;
140
+ var anchorName = activeNode.anchorName;
141
+ if (newActiveNode && (newActiveNode === null || newActiveNode === void 0 ? void 0 : newActiveNode.type.name) !== activeNode.nodeType && !(meta !== null && meta !== void 0 && meta.nodeMoved)) {
142
+ nodeType = newActiveNode.type.name;
143
+ anchorName = activeNode.anchorName.replace(activeNode.nodeType, nodeType);
144
+ }
145
+ var draghandleDec = (0, _decorations.dragHandleDecoration)(activeNode.pos, anchorName, nodeType, api);
131
146
  decorations = decorations.add(newState.doc, [draghandleDec]);
132
147
  }
133
148
  }
@@ -144,7 +159,8 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
144
159
  }
145
160
 
146
161
  // Add drop targets when node is being dragged
147
- if (meta !== null && meta !== void 0 && meta.isDragging && !tr.docChanged && api) {
162
+ // if the transaction is only for analytics and user is dragging, continue to draw drop targets
163
+ if (meta !== null && meta !== void 0 && meta.isDragging && (!tr.docChanged || tr.docChanged && isAnalyticTr) && api) {
148
164
  var _dropTargetDecoration = (0, _decorations.dropTargetDecorations)(oldState, newState, api),
149
165
  _decs = _dropTargetDecoration.decs,
150
166
  updatedDecorationState = _dropTargetDecoration.decorationState;
@@ -162,7 +178,7 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
162
178
  }
163
179
 
164
180
  // Map drop target decoration positions when the document changes
165
- if (tr.docChanged && currentState.isDragging) {
181
+ if (tr.docChanged && isDragging) {
166
182
  decorationState = decorationState.map(function (_ref8) {
167
183
  var index = _ref8.index,
168
184
  pos = _ref8.pos;
@@ -187,9 +203,9 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
187
203
  var isEmptyDoc = newState.doc.childCount === 1 && newState.doc.nodeSize <= 4;
188
204
  return {
189
205
  decorations: decorations,
190
- decorationState: (_decorationState = decorationState) !== null && _decorationState !== void 0 ? _decorationState : currentState.decorationState,
206
+ decorationState: decorationState,
191
207
  activeNode: isEmptyDoc ? null : (_meta$activeNode = meta === null || meta === void 0 ? void 0 : meta.activeNode) !== null && _meta$activeNode !== void 0 ? _meta$activeNode : mappedActiveNodePos,
192
- isDragging: (_meta$isDragging = meta === null || meta === void 0 ? void 0 : meta.isDragging) !== null && _meta$isDragging !== void 0 ? _meta$isDragging : currentState.isDragging,
208
+ isDragging: (_meta$isDragging = meta === null || meta === void 0 ? void 0 : meta.isDragging) !== null && _meta$isDragging !== void 0 ? _meta$isDragging : isDragging,
193
209
  isMenuOpen: meta !== null && meta !== void 0 && meta.toggleMenu ? !isMenuOpen : isMenuOpen,
194
210
  editorHeight: (_meta$editorHeight = meta === null || meta === void 0 ? void 0 : meta.editorHeight) !== null && _meta$editorHeight !== void 0 ? _meta$editorHeight : currentState.editorHeight,
195
211
  isResizerResizing: isResizerResizing,
@@ -231,7 +247,7 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
231
247
  return {
232
248
  destroy: function destroy() {
233
249
  resizeObserver.unobserve(dom);
234
- return pragmaticCleanup;
250
+ pragmaticCleanup();
235
251
  }
236
252
  };
237
253
  }
@@ -8,6 +8,7 @@ exports.DragHandle = void 0;
8
8
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
9
  var _react = require("react");
10
10
  var _react2 = require("@emotion/react");
11
+ var _analytics = require("@atlaskit/editor-common/analytics");
11
12
  var _hooks = require("@atlaskit/editor-common/hooks");
12
13
  var _dragHandler = _interopRequireDefault(require("@atlaskit/icon/glyph/drag-handler"));
13
14
  var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
@@ -19,6 +20,8 @@ var _consts = require("./consts");
19
20
  var _dragPreview = require("./drag-preview");
20
21
  /** @jsx jsx */
21
22
 
23
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
24
+
22
25
  var dragHandleButtonStyles = (0, _react2.css)({
23
26
  position: 'absolute',
24
27
  padding: "var(--ds-space-025, 2px)".concat(" 0"),
@@ -126,21 +129,31 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
126
129
  });
127
130
  },
128
131
  onDragStart: function onDragStart() {
129
- var _api$core5, _api$blockControls, _api$core6;
132
+ var _api$core5, _api$core6;
130
133
  if (start === undefined) {
131
134
  return;
132
135
  }
133
- api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.commands.setNodeDragged(start, anchorName, nodeType));
134
- api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 || _api$core6.actions.focus();
135
- },
136
- onDrop: function onDrop() {
137
- var _api$core7;
138
- api === null || api === void 0 || (_api$core7 = api.core) === null || _api$core7 === void 0 || _api$core7.actions.execute(function (_ref6) {
136
+ api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref6) {
137
+ var _api$blockControls, _api$analytics;
139
138
  var tr = _ref6.tr;
140
- return tr.setMeta(_main.key, {
141
- isDragging: false
139
+ api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.setNodeDragged(start, anchorName, nodeType)({
140
+ tr: tr
142
141
  });
142
+ var resolvedMovingNode = tr.doc.resolve(start);
143
+ var maybeNode = resolvedMovingNode.nodeAfter;
144
+ api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
145
+ eventType: _analytics.EVENT_TYPE.UI,
146
+ action: _analytics.ACTION.DRAGGED,
147
+ actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
148
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
149
+ attributes: {
150
+ nodeDepth: resolvedMovingNode.depth,
151
+ nodeType: (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name) || ''
152
+ }
153
+ })(tr);
154
+ return tr;
143
155
  });
156
+ api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 || _api$core6.actions.focus();
144
157
  }
145
158
  });
146
159
  }, [api, start, view, anchorName, nodeType]);
@@ -148,12 +161,9 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
148
161
  var positionStyles = (0, _react.useMemo)(function () {
149
162
  var supportsAnchor = CSS.supports('top', "anchor(".concat(anchorName, " start)")) && CSS.supports('left', "anchor(".concat(anchorName, " start)"));
150
163
  var dom = view.dom.querySelector("[data-drag-handler-anchor-name=\"".concat(anchorName, "\"]"));
151
- if (!dom) {
152
- return;
153
- }
154
164
  var hasResizer = anchorName.includes('table') || anchorName.includes('mediaSingle');
155
165
  var isExtension = anchorName.includes('extension') || anchorName.includes('bodiedExtension');
156
- var innerContainer = hasResizer ? dom.querySelector('.resizer-item') : isExtension ? dom.querySelector('.extension-container[data-layout]') : null;
166
+ var innerContainer = dom ? hasResizer ? dom.querySelector('.resizer-item') : isExtension ? dom.querySelector('.extension-container[data-layout]') : null : null;
157
167
  if (supportsAnchor) {
158
168
  return {
159
169
  left: hasResizer || isExtension ? (0, _dragHandlePositions.getLeftPosition)(dom, nodeType, innerContainer, macroInteractionUpdates) : "calc(anchor(".concat(anchorName, " start) - ").concat(_consts.DRAG_HANDLE_WIDTH, "px - ").concat((0, _consts.dragHandleGap)(nodeType), "px)"),
@@ -8,12 +8,13 @@ exports.DropTarget = void 0;
8
8
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
9
  var _react = require("react");
10
10
  var _react2 = require("@emotion/react");
11
- var _analytics = require("@atlaskit/editor-common/analytics");
12
11
  var _hooks = require("@atlaskit/editor-common/hooks");
13
12
  var _box = require("@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box");
14
13
  var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
15
14
  /** @jsx jsx */
16
15
 
16
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
17
+
17
18
  var DEFAULT_DROP_INDICATOR_WIDTH = 760;
18
19
  var styleDropTarget = (0, _react2.css)({
19
20
  height: "var(--ds-space-100, 8px)",
@@ -69,25 +70,9 @@ var DropTarget = exports.DropTarget = function DropTarget(_ref) {
69
70
  }) || {},
70
71
  pos = _ref3.pos;
71
72
  if (activeNode && pos !== undefined) {
72
- var _api$core;
73
+ var _api$core, _api$blockControls2;
73
74
  var start = activeNode.pos;
74
- api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (state) {
75
- var _api$blockControls2, _api$analytics;
76
- var resolvedMovingNode = state.tr.doc.resolve(start);
77
- var maybeNode = resolvedMovingNode.nodeAfter;
78
- api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || (_api$blockControls2 = _api$blockControls2.commands) === null || _api$blockControls2 === void 0 || _api$blockControls2.moveNode(start, pos)(state);
79
- api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
80
- eventType: _analytics.EVENT_TYPE.UI,
81
- action: _analytics.ACTION.DRAGGED,
82
- actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
83
- actionSubjectId: _analytics.ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
84
- attributes: {
85
- nodeDepth: resolvedMovingNode.depth,
86
- nodeType: (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name) || ''
87
- }
88
- })(state.tr);
89
- return state.tr;
90
- });
75
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || (_api$blockControls2 = _api$blockControls2.commands) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.moveNode(start, pos));
91
76
  }
92
77
  }
93
78
  });
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.GlobalStylesWrapper = void 0;
7
7
  var _react = require("@emotion/react");
8
8
  /** @jsx jsx */
9
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-global-styles -- Ignored via go/DSP-18766
9
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-global-styles, @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
10
10
 
11
11
  var globalStyles = (0, _react.css)({
12
12
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors -- Ignored via go/DSP-18766
@@ -12,6 +12,8 @@ var _bindEventListener = require("bind-event-listener");
12
12
  var _dragHandlePositions = require("../utils/drag-handle-positions");
13
13
  /** @jsx jsx */
14
14
 
15
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
16
+
15
17
  var basicStyles = (0, _react2.css)({
16
18
  position: 'absolute',
17
19
  width: '100%',
@@ -6,6 +6,9 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.getTopPosition = exports.getLeftPosition = void 0;
7
7
  var _consts = require("../ui/consts");
8
8
  var getTopPosition = exports.getTopPosition = function getTopPosition(dom) {
9
+ if (!dom) {
10
+ return 'auto';
11
+ }
9
12
  var table = dom.querySelector('table');
10
13
  if (table) {
11
14
  return "".concat(dom.offsetTop + ((table === null || table === void 0 ? void 0 : table.offsetTop) || 0), "px");
@@ -14,6 +17,9 @@ var getTopPosition = exports.getTopPosition = function getTopPosition(dom) {
14
17
  }
15
18
  };
16
19
  var getLeftPosition = exports.getLeftPosition = function getLeftPosition(dom, type, innerContainer, macroInteractionUpdates) {
20
+ if (!dom) {
21
+ return 'auto';
22
+ }
17
23
  if (!innerContainer) {
18
24
  return "".concat(dom.offsetLeft - (0, _consts.dragHandleGap)(type) - _consts.DRAG_HANDLE_WIDTH, "px");
19
25
  }
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
3
  import { createPlugin, key } from './pm-plugins/main';
3
4
  import { DragHandleMenu } from './ui/drag-handle-menu';
4
5
  import { GlobalStylesWrapper } from './ui/global-styles';
@@ -17,8 +18,9 @@ export const blockControlsPlugin = ({
17
18
  moveNode: (start, to) => ({
18
19
  tr
19
20
  }) => {
20
- var _node$nodeSize;
21
+ var _node$nodeSize, _api$analytics;
21
22
  const node = tr.doc.nodeAt(start);
23
+ const resolvedNode = tr.doc.resolve(start);
22
24
  if (!node) {
23
25
  return tr;
24
26
  }
@@ -33,6 +35,16 @@ export const blockControlsPlugin = ({
33
35
  nodeMoved: true
34
36
  });
35
37
  api === null || api === void 0 ? void 0 : api.core.actions.focus();
38
+ api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.attachAnalyticsEvent({
39
+ eventType: EVENT_TYPE.TRACK,
40
+ action: ACTION.MOVED,
41
+ actionSubject: ACTION_SUBJECT.ELEMENT,
42
+ actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
43
+ attributes: {
44
+ nodeDepth: resolvedNode.depth,
45
+ nodeType: node.type.name
46
+ }
47
+ })(tr);
36
48
  return tr;
37
49
  },
38
50
  showDragHandleAt: (pos, anchorName, nodeType) => ({
@@ -6,6 +6,7 @@ import { DropTarget } from '../ui/drop-target';
6
6
  import { MouseMoveWrapper } from '../ui/mouse-move-wrapper';
7
7
  export const dropTargetDecorations = (oldState, newState, api) => {
8
8
  const decs = [];
9
+ unmountDecorations('data-blocks-drop-target-container');
9
10
  // Decoration state is used to keep track of the position of the drop targets
10
11
  // and allows us to easily map the updated position in the plugin apply method.
11
12
  const decorationState = [];
@@ -16,6 +17,7 @@ export const dropTargetDecorations = (oldState, newState, api) => {
16
17
  });
17
18
  decs.push(Decoration.widget(pos, () => {
18
19
  const element = document.createElement('div');
20
+ element.setAttribute('data-blocks-drop-target-container', 'true');
19
21
  ReactDOM.render( /*#__PURE__*/createElement(DropTarget, {
20
22
  api,
21
23
  index
@@ -40,6 +42,7 @@ export const dropTargetDecorations = (oldState, newState, api) => {
40
42
  });
41
43
  decs.push(Decoration.widget(newState.doc.nodeSize - 2, () => {
42
44
  const element = document.createElement('div');
45
+ element.setAttribute('data-blocks-drop-target-container', 'true');
43
46
  ReactDOM.render( /*#__PURE__*/createElement(DropTarget, {
44
47
  api,
45
48
  index: decorationState.length
@@ -73,10 +76,12 @@ export const nodeDecorations = newState => {
73
76
  */
74
77
  export const mouseMoveWrapperDecorations = (newState, api) => {
75
78
  const decs = [];
79
+ unmountDecorations('data-blocks-decoration-container');
76
80
  newState.doc.descendants((node, pos, _parent, index) => {
77
81
  const anchorName = `--node-anchor-${node.type.name}-${index}`;
78
82
  decs.push(Decoration.widget(pos, (view, getPos) => {
79
83
  const element = document.createElement('div');
84
+ element.setAttribute('data-blocks-decoration-container', 'true');
80
85
  ReactDOM.render( /*#__PURE__*/createElement(MouseMoveWrapper, {
81
86
  view,
82
87
  api,
@@ -101,6 +106,7 @@ export const dragHandleDecoration = (pos, anchorName, nodeType, api) => {
101
106
  return Decoration.widget(pos, (view, getPos) => {
102
107
  const element = document.createElement('div');
103
108
  element.setAttribute('data-testid', 'block-ctrl-decorator-widget');
109
+ element.setAttribute('data-blocks-drag-handle-container', 'true');
104
110
  ReactDOM.render( /*#__PURE__*/createElement(DragHandle, {
105
111
  view,
106
112
  api,
@@ -111,6 +117,17 @@ export const dragHandleDecoration = (pos, anchorName, nodeType, api) => {
111
117
  return element;
112
118
  }, {
113
119
  side: -1,
114
- id: 'drag-handle'
120
+ id: 'drag-handle',
121
+ destroy: node => {
122
+ ReactDOM.unmountComponentAtNode(node);
123
+ }
124
+ });
125
+ };
126
+ const unmountDecorations = selector => {
127
+ // Removing decorations manually instead of using native destroy function in prosemirror API
128
+ // as it was more responsive and causes less re-rendering
129
+ const decorationsToRemove = document.querySelectorAll(`[${selector}="true"]`);
130
+ decorationsToRemove.forEach(el => {
131
+ ReactDOM.unmountComponentAtNode(el);
115
132
  });
116
133
  };
@@ -1,4 +1,5 @@
1
1
  import rafSchedule from 'raf-schd';
2
+ import { AnalyticsStep } from '@atlaskit/adf-schema/steps';
2
3
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
3
4
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
4
5
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
@@ -28,17 +29,16 @@ const destroyFn = api => {
28
29
  location,
29
30
  source
30
31
  }) => {
32
+ var _api$core;
31
33
  scrollable.style.setProperty('scroll-behavior', null);
32
-
33
- // if no drop targets are rendered, assume that drop is invalid
34
- if (location.current.dropTargets.length === 0) {
35
- var _api$core;
34
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
35
+ tr
36
+ }) => {
36
37
  const {
37
38
  start
38
39
  } = source.data;
39
- api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
40
- tr
41
- }) => {
40
+ // if no drop targets are rendered, assume that drop is invalid
41
+ if (location.current.dropTargets.length === 0) {
42
42
  var _api$analytics;
43
43
  const resolvedMovingNode = tr.doc.resolve(start);
44
44
  const maybeNode = resolvedMovingNode.nodeAfter;
@@ -52,9 +52,11 @@ const destroyFn = api => {
52
52
  nodeType: (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name) || ''
53
53
  }
54
54
  })(tr);
55
- return tr;
55
+ }
56
+ return tr.setMeta(key, {
57
+ isDragging: false
56
58
  });
57
- }
59
+ });
58
60
  }
59
61
  }));
60
62
  return combine(...cleanupFn);
@@ -81,7 +83,7 @@ export const createPlugin = api => {
81
83
  return initialState;
82
84
  },
83
85
  apply(tr, currentState, oldState, newState) {
84
- var _decorationState, _meta$activeNode, _meta$isDragging, _meta$editorHeight;
86
+ var _meta$activeNode, _meta$isDragging, _meta$editorHeight;
85
87
  if (initialState.isDocSizeLimitEnabled && newState.doc.nodeSize > DRAG_AND_DROP_DOC_SIZE_LIMIT) {
86
88
  return initialState;
87
89
  }
@@ -91,9 +93,13 @@ export const createPlugin = api => {
91
93
  isMenuOpen,
92
94
  decorationState,
93
95
  editorHeight,
94
- isResizerResizing
96
+ isResizerResizing,
97
+ isDragging
95
98
  } = currentState;
96
99
  const meta = tr.getMeta(key);
100
+ // when creating analytics during drag/drop events, PM thinks the doc has changed
101
+ // so tr.docChange is true and causes some decorations to not render
102
+ const isAnalyticTr = tr.steps.every(step => step instanceof AnalyticsStep);
97
103
 
98
104
  // If tables or media are being resized, we want to hide the drag handle
99
105
  const resizerMeta = tr.getMeta('is-resizer-resizing');
@@ -122,7 +128,14 @@ export const createPlugin = api => {
122
128
  // Note: Quite often the handle is not in the right position after a node is moved
123
129
  // it is safer for now to not show it when a node is moved
124
130
  if (activeNode && !(meta !== null && meta !== void 0 && meta.nodeMoved)) {
125
- const draghandleDec = dragHandleDecoration(activeNode.pos, activeNode.anchorName, activeNode.nodeType, api);
131
+ const newActiveNode = activeNode && tr.doc.nodeAt(tr.mapping.map(activeNode.pos));
132
+ let nodeType = activeNode.nodeType;
133
+ let anchorName = activeNode.anchorName;
134
+ if (newActiveNode && (newActiveNode === null || newActiveNode === void 0 ? void 0 : newActiveNode.type.name) !== activeNode.nodeType && !(meta !== null && meta !== void 0 && meta.nodeMoved)) {
135
+ nodeType = newActiveNode.type.name;
136
+ anchorName = activeNode.anchorName.replace(activeNode.nodeType, nodeType);
137
+ }
138
+ const draghandleDec = dragHandleDecoration(activeNode.pos, anchorName, nodeType, api);
126
139
  decorations = decorations.add(newState.doc, [draghandleDec]);
127
140
  }
128
141
  }
@@ -138,7 +151,8 @@ export const createPlugin = api => {
138
151
  }
139
152
 
140
153
  // Add drop targets when node is being dragged
141
- if (meta !== null && meta !== void 0 && meta.isDragging && !tr.docChanged && api) {
154
+ // if the transaction is only for analytics and user is dragging, continue to draw drop targets
155
+ if (meta !== null && meta !== void 0 && meta.isDragging && (!tr.docChanged || tr.docChanged && isAnalyticTr) && api) {
142
156
  const {
143
157
  decs,
144
158
  decorationState: updatedDecorationState
@@ -156,7 +170,7 @@ export const createPlugin = api => {
156
170
  }
157
171
 
158
172
  // Map drop target decoration positions when the document changes
159
- if (tr.docChanged && currentState.isDragging) {
173
+ if (tr.docChanged && isDragging) {
160
174
  decorationState = decorationState.map(({
161
175
  index,
162
176
  pos
@@ -182,9 +196,9 @@ export const createPlugin = api => {
182
196
  const isEmptyDoc = newState.doc.childCount === 1 && newState.doc.nodeSize <= 4;
183
197
  return {
184
198
  decorations,
185
- decorationState: (_decorationState = decorationState) !== null && _decorationState !== void 0 ? _decorationState : currentState.decorationState,
199
+ decorationState,
186
200
  activeNode: isEmptyDoc ? null : (_meta$activeNode = meta === null || meta === void 0 ? void 0 : meta.activeNode) !== null && _meta$activeNode !== void 0 ? _meta$activeNode : mappedActiveNodePos,
187
- isDragging: (_meta$isDragging = meta === null || meta === void 0 ? void 0 : meta.isDragging) !== null && _meta$isDragging !== void 0 ? _meta$isDragging : currentState.isDragging,
201
+ isDragging: (_meta$isDragging = meta === null || meta === void 0 ? void 0 : meta.isDragging) !== null && _meta$isDragging !== void 0 ? _meta$isDragging : isDragging,
188
202
  isMenuOpen: meta !== null && meta !== void 0 && meta.toggleMenu ? !isMenuOpen : isMenuOpen,
189
203
  editorHeight: (_meta$editorHeight = meta === null || meta === void 0 ? void 0 : meta.editorHeight) !== null && _meta$editorHeight !== void 0 ? _meta$editorHeight : currentState.editorHeight,
190
204
  isResizerResizing: isResizerResizing,
@@ -226,7 +240,7 @@ export const createPlugin = api => {
226
240
  return {
227
241
  destroy() {
228
242
  resizeObserver.unobserve(dom);
229
- return pragmaticCleanup;
243
+ pragmaticCleanup();
230
244
  }
231
245
  };
232
246
  }