@atlaskit/editor-plugin-block-controls 1.5.16 → 1.5.18

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,26 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 1.5.18
4
+
5
+ ### Patch Changes
6
+
7
+ - [#119419](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/119419)
8
+ [`a8b716b766200`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/a8b716b766200) -
9
+ [ux] Add shortcut to show and focus drag handle at selection"
10
+ - [#120359](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/120359)
11
+ [`f18f6e6b7f52c`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/f18f6e6b7f52c) -
12
+ fix drop targets hiding while dragging
13
+ - [#120426](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/120426)
14
+ [`0aface5be4428`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/0aface5be4428) -
15
+ Fix RangeErrors thrown by blocks plugin in prod
16
+ - Updated dependencies
17
+
18
+ ## 1.5.17
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies
23
+
3
24
  ## 1.5.16
4
25
 
5
26
  ### Patch Changes
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.showDragHandleAtSelection = void 0;
7
+ var showDragHandleAtSelection = exports.showDragHandleAtSelection = function showDragHandleAtSelection(api) {
8
+ return function (state, _, view) {
9
+ var rootPos = state.selection.$from.before(1);
10
+ var dom = view === null || view === void 0 ? void 0 : view.domAtPos(rootPos, 0);
11
+ var rootNode = dom === null || dom === void 0 ? void 0 : dom.node.childNodes[dom === null || dom === void 0 ? void 0 : dom.offset];
12
+ if (rootNode) {
13
+ var anchorName = rootNode.getAttribute('data-drag-handler-anchor-name');
14
+ var nodeType = rootNode.getAttribute('data-drag-handler-node-type');
15
+ if (api && anchorName && nodeType) {
16
+ api.core.actions.execute(api.blockControls.commands.showDragHandleAt(rootPos, anchorName, nodeType, {
17
+ isFocused: true
18
+ }));
19
+ return true;
20
+ }
21
+ }
22
+ return false;
23
+ };
24
+ };
@@ -58,14 +58,15 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
58
58
  return tr;
59
59
  };
60
60
  },
61
- showDragHandleAt: function showDragHandleAt(pos, anchorName, nodeType) {
61
+ showDragHandleAt: function showDragHandleAt(pos, anchorName, nodeType, handleOptions) {
62
62
  return function (_ref4) {
63
63
  var tr = _ref4.tr;
64
64
  tr.setMeta(_main.key, {
65
65
  activeNode: {
66
66
  pos: pos,
67
67
  anchorName: anchorName,
68
- nodeType: nodeType
68
+ nodeType: nodeType,
69
+ handleOptions: handleOptions
69
70
  }
70
71
  });
71
72
  return tr;
@@ -136,7 +136,7 @@ var mouseMoveWrapperDecorations = exports.mouseMoveWrapperDecorations = function
136
136
  });
137
137
  return decs;
138
138
  };
139
- var dragHandleDecoration = exports.dragHandleDecoration = function dragHandleDecoration(pos, anchorName, nodeType, api, getIntl) {
139
+ var dragHandleDecoration = exports.dragHandleDecoration = function dragHandleDecoration(api, getIntl, pos, anchorName, nodeType, handleOptions) {
140
140
  return _view.Decoration.widget(pos, function (view, getPos) {
141
141
  var element = document.createElement('div');
142
142
  // Need to set it to inline to avoid text being split when merging two paragraphs
@@ -155,7 +155,8 @@ var dragHandleDecoration = exports.dragHandleDecoration = function dragHandleDec
155
155
  api: api,
156
156
  getPos: getPos,
157
157
  anchorName: anchorName,
158
- nodeType: nodeType
158
+ nodeType: nodeType,
159
+ handleOptions: handleOptions
159
160
  })), element);
160
161
  return element;
161
162
  }, {
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.boundKeydownHandler = void 0;
7
+ var _keymaps = require("@atlaskit/editor-common/keymaps");
8
+ var _keymap = require("@atlaskit/editor-prosemirror/keymap");
9
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
10
+ var _showDragHandle = require("../commands/show-drag-handle");
11
+ function keymapList(api) {
12
+ var keymapList = {};
13
+ if (api && (0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_23873')) {
14
+ (0, _keymaps.bindKeymapWithCommand)(_keymaps.showElementDragHandle.common, function (state, dispatch, view) {
15
+ (0, _showDragHandle.showDragHandleAtSelection)(api)(state, dispatch, view);
16
+ //we always want to handle this shortcut to prevent default browser special char insert when option + alphabetical key is used
17
+ return true;
18
+ }, keymapList);
19
+ }
20
+ return keymapList;
21
+ }
22
+ var boundKeydownHandler = exports.boundKeydownHandler = function boundKeydownHandler(api) {
23
+ return (0, _keymap.keydownHandler)(keymapList(api));
24
+ };
@@ -19,6 +19,7 @@ var _combine = require("@atlaskit/pragmatic-drag-and-drop/combine");
19
19
  var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
20
20
  var _decorations = require("./decorations");
21
21
  var _handleMouseOver = require("./handle-mouse-over");
22
+ var _keymap = require("./keymap");
22
23
  var key = exports.key = new _state.PluginKey('blockControls');
23
24
  var destroyFn = function destroyFn(api) {
24
25
  var scrollable = document.querySelector('.fabric-editor-popup-scroll-parent');
@@ -92,7 +93,7 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
92
93
  return initialState;
93
94
  },
94
95
  apply: function apply(tr, currentState, oldState, newState) {
95
- var _meta$activeNode, _meta$activeNode2, _meta$isDragging, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging;
96
+ var _meta$activeNode, _meta$activeNode$hand, _meta$activeNode2, _meta$isDragging, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging;
96
97
  if (initialState.isDocSizeLimitEnabled === null) {
97
98
  if ((0, _platformFeatureFlags.fg)('platform.editor.elements.drag-and-drop-doc-size-limit_7k4vq')) {
98
99
  initialState.isDocSizeLimitEnabled = true;
@@ -125,9 +126,15 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
125
126
  var resizerMeta = tr.getMeta('is-resizer-resizing');
126
127
  isResizerResizing = resizerMeta !== null && resizerMeta !== void 0 ? resizerMeta : isResizerResizing;
127
128
  var nodeCountChanged = oldState.doc.childCount !== newState.doc.childCount;
129
+ var shouldRemoveHandle = true;
130
+ if ((0, _platformFeatureFlags.fg)('platform_editor_elements_drag_and_drop_ed_24000')) {
131
+ shouldRemoveHandle = !tr.getMeta('isRemote');
132
+ }
128
133
 
129
- // During resize, remove the drag handle widget
130
- if (isResizerResizing || nodeCountChanged || meta !== null && meta !== void 0 && meta.nodeMoved) {
134
+ // During resize, remove the drag handle widget so its dom positioning doesn't need to be maintained
135
+ // Also remove the handle when the node is moved or the node count changes. This helps prevent incorrect positioning
136
+ // Don't remove the handle if remote changes are changing the node count, its prosemirror position can be mapped instead
137
+ if (isResizerResizing || nodeCountChanged && shouldRemoveHandle || meta !== null && meta !== void 0 && meta.nodeMoved) {
131
138
  var oldHandle = decorations.find().filter(function (_ref5) {
132
139
  var spec = _ref5.spec;
133
140
  return spec.id === 'drag-handle';
@@ -163,7 +170,15 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
163
170
 
164
171
  // Draw node and mouseWrapper decorations at top level node if decorations is empty, editor height changes or node is moved
165
172
  if (redrawDecorations && !isResizerResizing && api) {
166
- decorations = _view.DecorationSet.create(newState.doc, []);
173
+ if ((0, _platformFeatureFlags.fg)('platform_editor_elements_drag_and_drop_ed_24000')) {
174
+ var oldNodeDecs = decorations.find().filter(function (_ref8) {
175
+ var spec = _ref8.spec;
176
+ return spec.type !== 'drop-target-decoration';
177
+ });
178
+ decorations = decorations.remove(oldNodeDecs);
179
+ } else {
180
+ decorations = _view.DecorationSet.create(newState.doc, []);
181
+ }
167
182
  var nodeDecs = (0, _decorations.nodeDecorations)(newState);
168
183
  if ((0, _platformFeatureFlags.fg)('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2')) {
169
184
  decorations = decorations.add(newState.doc, (0, _toConsumableArray2.default)(nodeDecs));
@@ -180,7 +195,9 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
180
195
 
181
196
  // When a node type changed to be nested inside another node, the position of the active node is off by 1
182
197
  // This is a workaround to fix the position of the active node when it is nested
183
- if (mappedPosisiton === prevMappedPos + 1) {
198
+
199
+ var shouldUpdateNestedPosition = (0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_24049') ? tr.docChanged && !nodeCountChanged : true;
200
+ if (shouldUpdateNestedPosition && mappedPosisiton === prevMappedPos + 1) {
184
201
  mappedPosisiton = prevMappedPos;
185
202
  }
186
203
  var newActiveNode = tr.doc.nodeAt(mappedPosisiton);
@@ -195,31 +212,31 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
195
212
  anchorName: anchorName
196
213
  };
197
214
  }
198
- var draghandleDec = (0, _decorations.dragHandleDecoration)(activeNode.pos, anchorName, nodeType, api, getIntl);
215
+ var draghandleDec = (0, _decorations.dragHandleDecoration)(api, getIntl, activeNode.pos, anchorName, nodeType);
199
216
  decorations = decorations.add(newState.doc, [draghandleDec]);
200
217
  }
201
218
  }
202
219
 
203
220
  // Remove previous drag handle widget and draw new drag handle widget when activeNode changes
204
- if (meta !== null && meta !== void 0 && meta.activeNode && (meta === null || meta === void 0 ? void 0 : meta.activeNode.pos) !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos) && (meta === null || meta === void 0 ? void 0 : meta.activeNode.anchorName) !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.anchorName) && api) {
205
- var _oldHandle = decorations.find().filter(function (_ref8) {
206
- var spec = _ref8.spec;
221
+ if (api && meta !== null && meta !== void 0 && meta.activeNode && ((meta === null || meta === void 0 ? void 0 : meta.activeNode.pos) !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos) && (meta === null || meta === void 0 ? void 0 : meta.activeNode.anchorName) !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.anchorName) || meta !== null && meta !== void 0 && (_meta$activeNode$hand = meta.activeNode.handleOptions) !== null && _meta$activeNode$hand !== void 0 && _meta$activeNode$hand.isFocused)) {
222
+ var _oldHandle = decorations.find().filter(function (_ref9) {
223
+ var spec = _ref9.spec;
207
224
  return spec.id === 'drag-handle';
208
225
  });
209
226
  decorations = decorations.remove(_oldHandle);
210
- var decs = (0, _decorations.dragHandleDecoration)(meta.activeNode.pos, meta.activeNode.anchorName, meta.activeNode.nodeType, api, getIntl);
227
+ var decs = (0, _decorations.dragHandleDecoration)(api, getIntl, meta.activeNode.pos, meta.activeNode.anchorName, meta.activeNode.nodeType, meta.activeNode.handleOptions);
211
228
  decorations = decorations.add(newState.doc, [decs]);
212
229
  }
213
230
  if ((0, _platformFeatureFlags.fg)('platform.editor.elements.drag-and-drop-ed-23816')) {
214
231
  var _activeNodeWithNewNod;
215
232
  // Remove previous drag handle widget and draw new drag handle widget when node type changes
216
233
  if (activeNodeWithNewNodeType && ((_activeNodeWithNewNod = activeNodeWithNewNodeType) === null || _activeNodeWithNewNod === void 0 ? void 0 : _activeNodeWithNewNod.nodeType) !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.nodeType) && api) {
217
- var _oldHandle2 = decorations.find().filter(function (_ref9) {
218
- var spec = _ref9.spec;
234
+ var _oldHandle2 = decorations.find().filter(function (_ref10) {
235
+ var spec = _ref10.spec;
219
236
  return spec.id === 'drag-handle';
220
237
  });
221
238
  decorations = decorations.remove(_oldHandle2);
222
- var _decs = (0, _decorations.dragHandleDecoration)(activeNodeWithNewNodeType.pos, activeNodeWithNewNodeType.anchorName, activeNodeWithNewNodeType.nodeType, api, getIntl);
239
+ var _decs = (0, _decorations.dragHandleDecoration)(api, getIntl, activeNodeWithNewNodeType.pos, activeNodeWithNewNodeType.anchorName, activeNodeWithNewNodeType.nodeType);
223
240
  decorations = decorations.add(newState.doc, [_decs]);
224
241
  }
225
242
  }
@@ -235,8 +252,8 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
235
252
 
236
253
  // Remove drop target decoration when dragging stops
237
254
  if ((meta === null || meta === void 0 ? void 0 : meta.isDragging) === false && !tr.docChanged) {
238
- var dropTargetDecs = decorations.find().filter(function (_ref10) {
239
- var spec = _ref10.spec;
255
+ var dropTargetDecs = decorations.find().filter(function (_ref11) {
256
+ var spec = _ref11.spec;
240
257
  return spec.type === 'drop-target-decoration';
241
258
  });
242
259
  decorations = decorations.remove(dropTargetDecs);
@@ -244,9 +261,9 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
244
261
 
245
262
  // Map drop target decoration positions when the document changes
246
263
  if (tr.docChanged && isDragging) {
247
- decorationState = decorationState.map(function (_ref11) {
248
- var index = _ref11.index,
249
- pos = _ref11.pos;
264
+ decorationState = decorationState.map(function (_ref12) {
265
+ var index = _ref12.index,
266
+ pos = _ref12.pos;
250
267
  return {
251
268
  index: index,
252
269
  pos: tr.mapping.map(pos)
@@ -259,8 +276,8 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
259
276
  decorations = decorations.map(tr.mapping, tr.doc);
260
277
  }
261
278
  var isEmptyDoc = newState.doc.childCount === 1 && newState.doc.nodeSize <= 4;
262
- var hasNodeDecoration = decorations.find().some(function (_ref12) {
263
- var spec = _ref12.spec;
279
+ var hasNodeDecoration = decorations.find().some(function (_ref13) {
280
+ var spec = _ref13.spec;
264
281
  return spec.type === 'node-decoration';
265
282
  });
266
283
  if (!hasNodeDecoration && isEmptyDoc) {
@@ -379,6 +396,15 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
379
396
  return true;
380
397
  }
381
398
  }
399
+
400
+ //NOTE: altKey === 'option' on MacOS
401
+ if (event.altKey && event.shiftKey && event.ctrlKey && (0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_23873')) {
402
+ //prevent holding down key combo from firing repeatedly
403
+ if (!event.repeat && (0, _keymap.boundKeydownHandler)(api)(view, event)) {
404
+ event.preventDefault();
405
+ return true;
406
+ }
407
+ }
382
408
  return false;
383
409
  }
384
410
  }
@@ -391,7 +417,8 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
391
417
  if (!(0, _platformFeatureFlags.fg)('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2')) {
392
418
  // Use ResizeObserver to observe height changes
393
419
  resizeObserverHeight = new ResizeObserver((0, _rafSchd.default)(function (entries) {
394
- var editorHeight = entries[0].contentBoxSize[0].blockSize;
420
+ var _entries$;
421
+ var editorHeight = (_entries$ = entries[0]) === null || _entries$ === void 0 || (_entries$ = _entries$.contentBoxSize[0]) === null || _entries$ === void 0 ? void 0 : _entries$.blockSize;
395
422
 
396
423
  // Update the plugin state when the height changes
397
424
  var pluginState = key.getState(editorView.state);
@@ -401,7 +428,7 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
401
428
  if ((pluginState === null || pluginState === void 0 ? void 0 : pluginState.isResizerResizing) !== isResizerResizing) {
402
429
  transaction.setMeta('is-resizer-resizing', isResizerResizing);
403
430
  }
404
- if (!isResizerResizing) {
431
+ if (!isResizerResizing && editorHeight) {
405
432
  transaction.setMeta(key, {
406
433
  editorHeight: editorHeight
407
434
  });
@@ -48,11 +48,15 @@ var dragHandleButtonStyles = (0, _react2.css)({
48
48
  cursor: 'grab',
49
49
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
50
50
  zIndex: _consts.DRAG_HANDLE_ZINDEX,
51
+ outline: 'none',
51
52
  '&:hover': {
52
53
  backgroundColor: "var(--ds-background-neutral-subtle-hovered, #091E420F)"
53
54
  },
54
55
  '&:active': {
55
56
  backgroundColor: "var(--ds-background-neutral-subtle-pressed, #091E4224)"
57
+ },
58
+ '&:focus': {
59
+ outline: "2px solid ".concat("var(--ds-border-focused, #388BFF)")
56
60
  }
57
61
  });
58
62
  var selectedStyles = (0, _react2.css)({
@@ -65,7 +69,8 @@ var DragHandleInternal = function DragHandleInternal(_ref) {
65
69
  getPos = _ref.getPos,
66
70
  anchorName = _ref.anchorName,
67
71
  nodeType = _ref.nodeType,
68
- formatMessage = _ref.intl.formatMessage;
72
+ formatMessage = _ref.intl.formatMessage,
73
+ handleOptions = _ref.handleOptions;
69
74
  var start = getPos();
70
75
  var buttonRef = (0, _react.useRef)(null);
71
76
  var _useState = (0, _react.useState)(768),
@@ -168,6 +173,34 @@ var DragHandleInternal = function DragHandleInternal(_ref) {
168
173
  return tr;
169
174
  });
170
175
  }, [start, api]);
176
+ var handleKeyDown = (0, _react.useCallback)(function (e) {
177
+ if ((0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_23873')) {
178
+ // allow user to use spacebar to select the node
179
+ if (!e.repeat && e.key === ' ') {
180
+ var _api$core4;
181
+ api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(function (_ref5) {
182
+ var tr = _ref5.tr;
183
+ if (start === undefined) {
184
+ return tr;
185
+ }
186
+ var node = tr.doc.nodeAt(start);
187
+ if (!node) {
188
+ return tr;
189
+ }
190
+ var $startPos = tr.doc.resolve(start + node.nodeSize);
191
+ var selection = new _state.TextSelection($startPos);
192
+ tr.setSelection(selection);
193
+ tr.setMeta(_main.key, {
194
+ pos: start
195
+ });
196
+ return tr;
197
+ });
198
+ } else {
199
+ // return focus to editor to resume editing from caret positon
200
+ view.focus();
201
+ }
202
+ }
203
+ }, [start, api, view]);
171
204
  (0, _react.useEffect)(function () {
172
205
  var element = buttonRef.current;
173
206
  if (!element) {
@@ -181,11 +214,11 @@ var DragHandleInternal = function DragHandleInternal(_ref) {
181
214
  start: start
182
215
  };
183
216
  },
184
- onGenerateDragPreview: function onGenerateDragPreview(_ref5) {
185
- var nativeSetDragImage = _ref5.nativeSetDragImage;
217
+ onGenerateDragPreview: function onGenerateDragPreview(_ref6) {
218
+ var nativeSetDragImage = _ref6.nativeSetDragImage;
186
219
  (0, _setCustomNativeDragPreview.setCustomNativeDragPreview)({
187
- render: function render(_ref6) {
188
- var container = _ref6.container;
220
+ render: function render(_ref7) {
221
+ var container = _ref7.container;
189
222
  var dom = view.dom.querySelector("[data-drag-handler-anchor-name=\"".concat(anchorName, "\"]"));
190
223
  if (!dom) {
191
224
  return;
@@ -196,13 +229,13 @@ var DragHandleInternal = function DragHandleInternal(_ref) {
196
229
  });
197
230
  },
198
231
  onDragStart: function onDragStart() {
199
- var _api$core4;
232
+ var _api$core5;
200
233
  if (start === undefined) {
201
234
  return;
202
235
  }
203
- api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(function (_ref7) {
236
+ api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref8) {
204
237
  var _api$blockControls, _api$analytics2;
205
- var tr = _ref7.tr;
238
+ var tr = _ref8.tr;
206
239
  api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.setNodeDragged(start, anchorName, nodeType)({
207
240
  tr: tr
208
241
  });
@@ -260,6 +293,18 @@ var DragHandleInternal = function DragHandleInternal(_ref) {
260
293
  top: (0, _platformFeatureFlags.fg)('platform_editor_elements_dnd_ed_23674') ? (0, _dragHandlePositions.getTopPosition)(dom, nodeType) : (0, _dragHandlePositions.getTopPosition)(dom)
261
294
  };
262
295
  }, [anchorName, nodeType, view, blockCardWidth, macroInteractionUpdates]);
296
+ (0, _react.useEffect)(function () {
297
+ if (handleOptions !== null && handleOptions !== void 0 && handleOptions.isFocused && buttonRef.current && (0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_23873')) {
298
+ var id = requestAnimationFrame(function () {
299
+ var _buttonRef$current;
300
+ (_buttonRef$current = buttonRef.current) === null || _buttonRef$current === void 0 || _buttonRef$current.focus();
301
+ });
302
+ return function () {
303
+ cancelAnimationFrame(id);
304
+ view.focus();
305
+ };
306
+ }
307
+ }, [buttonRef, handleOptions === null || handleOptions === void 0 ? void 0 : handleOptions.isFocused, view]);
263
308
  var helpDescriptors = [{
264
309
  description: formatMessage(_messages.blockControlsMessages.dragToMove)
265
310
  }, {
@@ -279,6 +324,7 @@ var DragHandleInternal = function DragHandleInternal(_ref) {
279
324
  style: positionStyles,
280
325
  onClick: handleOnClick,
281
326
  onMouseDown: (0, _platformFeatureFlags.fg)('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2') ? handleMouseDownWrapperRemoved : handleMouseDown,
327
+ onKeyDown: handleKeyDown,
282
328
  "data-testid": "block-ctrl-drag-handle"
283
329
  }, (0, _react2.jsx)(_dragHandler.default, {
284
330
  label: "",
@@ -0,0 +1,16 @@
1
+ export const showDragHandleAtSelection = api => (state, _, view) => {
2
+ const rootPos = state.selection.$from.before(1);
3
+ const dom = view === null || view === void 0 ? void 0 : view.domAtPos(rootPos, 0);
4
+ const rootNode = dom === null || dom === void 0 ? void 0 : dom.node.childNodes[dom === null || dom === void 0 ? void 0 : dom.offset];
5
+ if (rootNode) {
6
+ const anchorName = rootNode.getAttribute('data-drag-handler-anchor-name');
7
+ const nodeType = rootNode.getAttribute('data-drag-handler-node-type');
8
+ if (api && anchorName && nodeType) {
9
+ api.core.actions.execute(api.blockControls.commands.showDragHandleAt(rootPos, anchorName, nodeType, {
10
+ isFocused: true
11
+ }));
12
+ return true;
13
+ }
14
+ }
15
+ return false;
16
+ };
@@ -49,14 +49,15 @@ export const blockControlsPlugin = ({
49
49
  })(tr);
50
50
  return tr;
51
51
  },
52
- showDragHandleAt: (pos, anchorName, nodeType) => ({
52
+ showDragHandleAt: (pos, anchorName, nodeType, handleOptions) => ({
53
53
  tr
54
54
  }) => {
55
55
  tr.setMeta(key, {
56
56
  activeNode: {
57
57
  pos,
58
58
  anchorName,
59
- nodeType
59
+ nodeType,
60
+ handleOptions
60
61
  }
61
62
  });
62
63
  return tr;
@@ -130,7 +130,7 @@ export const mouseMoveWrapperDecorations = (newState, api) => {
130
130
  });
131
131
  return decs;
132
132
  };
133
- export const dragHandleDecoration = (pos, anchorName, nodeType, api, getIntl) => {
133
+ export const dragHandleDecoration = (api, getIntl, pos, anchorName, nodeType, handleOptions) => {
134
134
  return Decoration.widget(pos, (view, getPos) => {
135
135
  const element = document.createElement('div');
136
136
  // Need to set it to inline to avoid text being split when merging two paragraphs
@@ -149,7 +149,8 @@ export const dragHandleDecoration = (pos, anchorName, nodeType, api, getIntl) =>
149
149
  api,
150
150
  getPos,
151
151
  anchorName,
152
- nodeType
152
+ nodeType,
153
+ handleOptions
153
154
  })), element);
154
155
  return element;
155
156
  }, {
@@ -0,0 +1,16 @@
1
+ import { bindKeymapWithCommand, showElementDragHandle } from '@atlaskit/editor-common/keymaps';
2
+ import { keydownHandler } from '@atlaskit/editor-prosemirror/keymap';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
4
+ import { showDragHandleAtSelection } from '../commands/show-drag-handle';
5
+ function keymapList(api) {
6
+ let keymapList = {};
7
+ if (api && fg('platform_editor_element_drag_and_drop_ed_23873')) {
8
+ bindKeymapWithCommand(showElementDragHandle.common, (state, dispatch, view) => {
9
+ showDragHandleAtSelection(api)(state, dispatch, view);
10
+ //we always want to handle this shortcut to prevent default browser special char insert when option + alphabetical key is used
11
+ return true;
12
+ }, keymapList);
13
+ }
14
+ return keymapList;
15
+ }
16
+ export const boundKeydownHandler = api => keydownHandler(keymapList(api));
@@ -11,6 +11,7 @@ import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
11
11
  import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
12
12
  import { dragHandleDecoration, dropTargetDecorations, emptyParagraphNodeDecorations, mouseMoveWrapperDecorations, nodeDecorations } from './decorations';
13
13
  import { handleMouseOver } from './handle-mouse-over';
14
+ import { boundKeydownHandler } from './keymap';
14
15
  export const key = new PluginKey('blockControls');
15
16
  const destroyFn = api => {
16
17
  const scrollable = document.querySelector('.fabric-editor-popup-scroll-parent');
@@ -86,7 +87,7 @@ export const createPlugin = (api, getIntl) => {
86
87
  return initialState;
87
88
  },
88
89
  apply(tr, currentState, oldState, newState) {
89
- var _meta$activeNode, _meta$activeNode2, _meta$isDragging, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging;
90
+ var _meta$activeNode, _meta$activeNode$hand, _meta$activeNode2, _meta$isDragging, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging;
90
91
  if (initialState.isDocSizeLimitEnabled === null) {
91
92
  if (fg('platform.editor.elements.drag-and-drop-doc-size-limit_7k4vq')) {
92
93
  initialState.isDocSizeLimitEnabled = true;
@@ -119,9 +120,15 @@ export const createPlugin = (api, getIntl) => {
119
120
  const resizerMeta = tr.getMeta('is-resizer-resizing');
120
121
  isResizerResizing = resizerMeta !== null && resizerMeta !== void 0 ? resizerMeta : isResizerResizing;
121
122
  const nodeCountChanged = oldState.doc.childCount !== newState.doc.childCount;
123
+ let shouldRemoveHandle = true;
124
+ if (fg('platform_editor_elements_drag_and_drop_ed_24000')) {
125
+ shouldRemoveHandle = !tr.getMeta('isRemote');
126
+ }
122
127
 
123
- // During resize, remove the drag handle widget
124
- if (isResizerResizing || nodeCountChanged || meta !== null && meta !== void 0 && meta.nodeMoved) {
128
+ // During resize, remove the drag handle widget so its dom positioning doesn't need to be maintained
129
+ // Also remove the handle when the node is moved or the node count changes. This helps prevent incorrect positioning
130
+ // Don't remove the handle if remote changes are changing the node count, its prosemirror position can be mapped instead
131
+ if (isResizerResizing || nodeCountChanged && shouldRemoveHandle || meta !== null && meta !== void 0 && meta.nodeMoved) {
125
132
  const oldHandle = decorations.find().filter(({
126
133
  spec
127
134
  }) => spec.id === 'drag-handle');
@@ -154,7 +161,14 @@ export const createPlugin = (api, getIntl) => {
154
161
 
155
162
  // Draw node and mouseWrapper decorations at top level node if decorations is empty, editor height changes or node is moved
156
163
  if (redrawDecorations && !isResizerResizing && api) {
157
- decorations = DecorationSet.create(newState.doc, []);
164
+ if (fg('platform_editor_elements_drag_and_drop_ed_24000')) {
165
+ const oldNodeDecs = decorations.find().filter(({
166
+ spec
167
+ }) => spec.type !== 'drop-target-decoration');
168
+ decorations = decorations.remove(oldNodeDecs);
169
+ } else {
170
+ decorations = DecorationSet.create(newState.doc, []);
171
+ }
158
172
  const nodeDecs = nodeDecorations(newState);
159
173
  if (fg('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2')) {
160
174
  decorations = decorations.add(newState.doc, [...nodeDecs]);
@@ -171,7 +185,9 @@ export const createPlugin = (api, getIntl) => {
171
185
 
172
186
  // When a node type changed to be nested inside another node, the position of the active node is off by 1
173
187
  // This is a workaround to fix the position of the active node when it is nested
174
- if (mappedPosisiton === prevMappedPos + 1) {
188
+
189
+ const shouldUpdateNestedPosition = fg('platform_editor_element_drag_and_drop_ed_24049') ? tr.docChanged && !nodeCountChanged : true;
190
+ if (shouldUpdateNestedPosition && mappedPosisiton === prevMappedPos + 1) {
175
191
  mappedPosisiton = prevMappedPos;
176
192
  }
177
193
  const newActiveNode = tr.doc.nodeAt(mappedPosisiton);
@@ -186,18 +202,18 @@ export const createPlugin = (api, getIntl) => {
186
202
  anchorName
187
203
  };
188
204
  }
189
- const draghandleDec = dragHandleDecoration(activeNode.pos, anchorName, nodeType, api, getIntl);
205
+ const draghandleDec = dragHandleDecoration(api, getIntl, activeNode.pos, anchorName, nodeType);
190
206
  decorations = decorations.add(newState.doc, [draghandleDec]);
191
207
  }
192
208
  }
193
209
 
194
210
  // Remove previous drag handle widget and draw new drag handle widget when activeNode changes
195
- if (meta !== null && meta !== void 0 && meta.activeNode && (meta === null || meta === void 0 ? void 0 : meta.activeNode.pos) !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos) && (meta === null || meta === void 0 ? void 0 : meta.activeNode.anchorName) !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.anchorName) && api) {
211
+ if (api && meta !== null && meta !== void 0 && meta.activeNode && ((meta === null || meta === void 0 ? void 0 : meta.activeNode.pos) !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos) && (meta === null || meta === void 0 ? void 0 : meta.activeNode.anchorName) !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.anchorName) || meta !== null && meta !== void 0 && (_meta$activeNode$hand = meta.activeNode.handleOptions) !== null && _meta$activeNode$hand !== void 0 && _meta$activeNode$hand.isFocused)) {
196
212
  const oldHandle = decorations.find().filter(({
197
213
  spec
198
214
  }) => spec.id === 'drag-handle');
199
215
  decorations = decorations.remove(oldHandle);
200
- const decs = dragHandleDecoration(meta.activeNode.pos, meta.activeNode.anchorName, meta.activeNode.nodeType, api, getIntl);
216
+ const decs = dragHandleDecoration(api, getIntl, meta.activeNode.pos, meta.activeNode.anchorName, meta.activeNode.nodeType, meta.activeNode.handleOptions);
201
217
  decorations = decorations.add(newState.doc, [decs]);
202
218
  }
203
219
  if (fg('platform.editor.elements.drag-and-drop-ed-23816')) {
@@ -208,7 +224,7 @@ export const createPlugin = (api, getIntl) => {
208
224
  spec
209
225
  }) => spec.id === 'drag-handle');
210
226
  decorations = decorations.remove(oldHandle);
211
- const decs = dragHandleDecoration(activeNodeWithNewNodeType.pos, activeNodeWithNewNodeType.anchorName, activeNodeWithNewNodeType.nodeType, api, getIntl);
227
+ const decs = dragHandleDecoration(api, getIntl, activeNodeWithNewNodeType.pos, activeNodeWithNewNodeType.anchorName, activeNodeWithNewNodeType.nodeType);
212
228
  decorations = decorations.add(newState.doc, [decs]);
213
229
  }
214
230
  }
@@ -373,6 +389,15 @@ export const createPlugin = (api, getIntl) => {
373
389
  return true;
374
390
  }
375
391
  }
392
+
393
+ //NOTE: altKey === 'option' on MacOS
394
+ if (event.altKey && event.shiftKey && event.ctrlKey && fg('platform_editor_element_drag_and_drop_ed_23873')) {
395
+ //prevent holding down key combo from firing repeatedly
396
+ if (!event.repeat && boundKeydownHandler(api)(view, event)) {
397
+ event.preventDefault();
398
+ return true;
399
+ }
400
+ }
376
401
  return false;
377
402
  }
378
403
  }
@@ -385,7 +410,8 @@ export const createPlugin = (api, getIntl) => {
385
410
  if (!fg('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2')) {
386
411
  // Use ResizeObserver to observe height changes
387
412
  resizeObserverHeight = new ResizeObserver(rafSchedule(entries => {
388
- const editorHeight = entries[0].contentBoxSize[0].blockSize;
413
+ var _entries$, _entries$$contentBoxS;
414
+ const editorHeight = (_entries$ = entries[0]) === null || _entries$ === void 0 ? void 0 : (_entries$$contentBoxS = _entries$.contentBoxSize[0]) === null || _entries$$contentBoxS === void 0 ? void 0 : _entries$$contentBoxS.blockSize;
389
415
 
390
416
  // Update the plugin state when the height changes
391
417
  const pluginState = key.getState(editorView.state);
@@ -395,7 +421,7 @@ export const createPlugin = (api, getIntl) => {
395
421
  if ((pluginState === null || pluginState === void 0 ? void 0 : pluginState.isResizerResizing) !== isResizerResizing) {
396
422
  transaction.setMeta('is-resizer-resizing', isResizerResizing);
397
423
  }
398
- if (!isResizerResizing) {
424
+ if (!isResizerResizing && editorHeight) {
399
425
  transaction.setMeta(key, {
400
426
  editorHeight
401
427
  });