@atlaskit/editor-plugin-block-controls 1.5.17 → 1.5.19

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.
@@ -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
  });
@@ -1,8 +1,8 @@
1
1
  /** @jsx jsx */
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
-
4
3
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
5
4
  import { css, jsx } from '@emotion/react';
5
+ import { bind } from 'bind-event-listener';
6
6
  import { injectIntl } from 'react-intl-next';
7
7
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
8
8
  import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
@@ -39,11 +39,15 @@ const dragHandleButtonStyles = css({
39
39
  cursor: 'grab',
40
40
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
41
41
  zIndex: DRAG_HANDLE_ZINDEX,
42
+ outline: 'none',
42
43
  '&:hover': {
43
44
  backgroundColor: "var(--ds-background-neutral-subtle-hovered, #091E420F)"
44
45
  },
45
46
  '&:active': {
46
47
  backgroundColor: "var(--ds-background-neutral-subtle-pressed, #091E4224)"
48
+ },
49
+ '&:focus': {
50
+ outline: `2px solid ${"var(--ds-border-focused, #388BFF)"}`
47
51
  }
48
52
  });
49
53
  const selectedStyles = css({
@@ -58,7 +62,8 @@ const DragHandleInternal = ({
58
62
  nodeType,
59
63
  intl: {
60
64
  formatMessage
61
- }
65
+ },
66
+ handleOptions
62
67
  }) => {
63
68
  const start = getPos();
64
69
  const buttonRef = useRef(null);
@@ -158,6 +163,35 @@ const DragHandleInternal = ({
158
163
  return tr;
159
164
  });
160
165
  }, [start, api]);
166
+ const handleKeyDown = useCallback(e => {
167
+ if (fg('platform_editor_element_drag_and_drop_ed_23873')) {
168
+ // allow user to use spacebar to select the node
169
+ if (!e.repeat && e.key === ' ') {
170
+ var _api$core4;
171
+ api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions.execute(({
172
+ tr
173
+ }) => {
174
+ if (start === undefined) {
175
+ return tr;
176
+ }
177
+ const node = tr.doc.nodeAt(start);
178
+ if (!node) {
179
+ return tr;
180
+ }
181
+ const $startPos = tr.doc.resolve(start + node.nodeSize);
182
+ const selection = new TextSelection($startPos);
183
+ tr.setSelection(selection);
184
+ tr.setMeta(key, {
185
+ pos: start
186
+ });
187
+ return tr;
188
+ });
189
+ } else {
190
+ // return focus to editor to resume editing from caret positon
191
+ view.focus();
192
+ }
193
+ }
194
+ }, [start, api, view]);
161
195
  useEffect(() => {
162
196
  const element = buttonRef.current;
163
197
  if (!element) {
@@ -186,11 +220,11 @@ const DragHandleInternal = ({
186
220
  });
187
221
  },
188
222
  onDragStart() {
189
- var _api$core4;
223
+ var _api$core5;
190
224
  if (start === undefined) {
191
225
  return;
192
226
  }
193
- api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions.execute(({
227
+ api === null || api === void 0 ? void 0 : (_api$core5 = api.core) === null || _api$core5 === void 0 ? void 0 : _api$core5.actions.execute(({
194
228
  tr
195
229
  }) => {
196
230
  var _api$blockControls, _api$analytics2;
@@ -217,7 +251,7 @@ const DragHandleInternal = ({
217
251
  });
218
252
  }, [anchorName, api, nodeType, view, start]);
219
253
  const macroInteractionUpdates = featureFlagsState === null || featureFlagsState === void 0 ? void 0 : featureFlagsState.macroInteractionUpdates;
220
- const positionStyles = useMemo(() => {
254
+ const calculatePosition = useCallback(() => {
221
255
  const supportsAnchor = CSS.supports('top', `anchor(${anchorName} start)`) && CSS.supports('left', `anchor(${anchorName} start)`);
222
256
  const dom = view.dom.querySelector(`[data-drag-handler-anchor-name="${anchorName}"]`);
223
257
  const hasResizer = nodeType === 'table' || nodeType === 'mediaSingle';
@@ -239,18 +273,68 @@ const DragHandleInternal = ({
239
273
  }
240
274
  if (supportsAnchor) {
241
275
  return fg('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2') ? {
242
- left: hasResizer || isExtension || isEmbedCard ? `calc(anchor(${anchorName} start) + ${getLeftPosition(dom, nodeType, innerContainer, macroInteractionUpdates)})` : `calc(anchor(${anchorName} start) - ${DRAG_HANDLE_WIDTH}px - ${dragHandleGap(nodeType)}px)`,
276
+ left: hasResizer || isExtension || isEmbedCard || isBlockCard && innerContainer ? `calc(anchor(${anchorName} start) + ${getLeftPosition(dom, nodeType, innerContainer, macroInteractionUpdates)})` : `calc(anchor(${anchorName} start) - ${DRAG_HANDLE_WIDTH}px - ${dragHandleGap(nodeType)}px)`,
243
277
  top: fg('platform_editor_elements_dnd_ed_23674') ? `calc(anchor(${anchorName} start) + ${topPositionAdjustment(nodeType)}px)` : anchorName.includes('table') ? `calc(anchor(${anchorName} start) + ${DRAG_HANDLE_HEIGHT}px)` : `anchor(${anchorName} start)`
244
278
  } : {
245
279
  left: hasResizer || isExtension || isBlockCard || isEmbedCard ? getLeftPosition(dom, nodeType, innerContainer, macroInteractionUpdates) : `calc(anchor(${anchorName} start) - ${DRAG_HANDLE_WIDTH}px - ${dragHandleGap(nodeType)}px)`,
246
280
  top: fg('platform_editor_elements_dnd_ed_23674') ? `calc(anchor(${anchorName} start) + ${topPositionAdjustment(nodeType)}px)` : anchorName.includes('table') ? `calc(anchor(${anchorName} start) + ${DRAG_HANDLE_HEIGHT}px)` : `anchor(${anchorName} start)`
247
281
  };
248
282
  }
249
- return {
283
+ return fg('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2') ? {
284
+ left: hasResizer || isExtension || isEmbedCard || isBlockCard && innerContainer ? `calc(${(dom === null || dom === void 0 ? void 0 : dom.offsetLeft) || 0}px + ${getLeftPosition(dom, nodeType, innerContainer, macroInteractionUpdates)})` : getLeftPosition(dom, nodeType, innerContainer, macroInteractionUpdates),
285
+ top: fg('platform_editor_elements_dnd_ed_23674') ? getTopPosition(dom, nodeType) : getTopPosition(dom)
286
+ } : {
250
287
  left: getLeftPosition(dom, nodeType, innerContainer, macroInteractionUpdates),
251
288
  top: fg('platform_editor_elements_dnd_ed_23674') ? getTopPosition(dom, nodeType) : getTopPosition(dom)
252
289
  };
253
290
  }, [anchorName, nodeType, view, blockCardWidth, macroInteractionUpdates]);
291
+ const [newPositionStyles, setNewPositionStyles] = useState({
292
+ display: 'none'
293
+ });
294
+ useEffect(() => {
295
+ if (!fg('platform_editor_element_drag_and_drop_ed_23896')) {
296
+ return;
297
+ }
298
+ let cleanUpTransitionListener;
299
+ if (nodeType === 'extension' || nodeType === 'embedCard') {
300
+ const dom = view.dom.querySelector(`[data-drag-handler-anchor-name="${anchorName}"]`);
301
+ if (!dom) {
302
+ return;
303
+ }
304
+ cleanUpTransitionListener = bind(dom, {
305
+ type: 'transitionend',
306
+ listener: () => {
307
+ setNewPositionStyles(calculatePosition());
308
+ }
309
+ });
310
+ }
311
+ const calcPos = requestAnimationFrame(() => {
312
+ setNewPositionStyles(calculatePosition());
313
+ });
314
+ return () => {
315
+ var _cleanUpTransitionLis;
316
+ cancelAnimationFrame(calcPos);
317
+ (_cleanUpTransitionLis = cleanUpTransitionListener) === null || _cleanUpTransitionLis === void 0 ? void 0 : _cleanUpTransitionLis();
318
+ };
319
+ }, [calculatePosition, view.dom, anchorName, nodeType]);
320
+ const positionStyles = useMemo(() => {
321
+ if (fg('platform_editor_element_drag_and_drop_ed_23896')) {
322
+ return newPositionStyles;
323
+ }
324
+ return calculatePosition();
325
+ }, [calculatePosition, newPositionStyles]);
326
+ useEffect(() => {
327
+ if (handleOptions !== null && handleOptions !== void 0 && handleOptions.isFocused && buttonRef.current && fg('platform_editor_element_drag_and_drop_ed_23873')) {
328
+ const id = requestAnimationFrame(() => {
329
+ var _buttonRef$current;
330
+ (_buttonRef$current = buttonRef.current) === null || _buttonRef$current === void 0 ? void 0 : _buttonRef$current.focus();
331
+ });
332
+ return () => {
333
+ cancelAnimationFrame(id);
334
+ view.focus();
335
+ };
336
+ }
337
+ }, [buttonRef, handleOptions === null || handleOptions === void 0 ? void 0 : handleOptions.isFocused, view]);
254
338
  const helpDescriptors = [{
255
339
  description: formatMessage(blockControlsMessages.dragToMove)
256
340
  }, {
@@ -266,9 +350,10 @@ const DragHandleInternal = ({
266
350
  ref: buttonRef
267
351
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
268
352
  ,
269
- style: positionStyles,
353
+ style: fg('platform_editor_element_drag_and_drop_ed_23896') ? newPositionStyles : positionStyles,
270
354
  onClick: handleOnClick,
271
355
  onMouseDown: fg('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2') ? handleMouseDownWrapperRemoved : handleMouseDown,
356
+ onKeyDown: handleKeyDown,
272
357
  "data-testid": "block-ctrl-drag-handle"
273
358
  }, jsx(DragHandlerIcon, {
274
359
  label: "",
@@ -0,0 +1,18 @@
1
+ export var showDragHandleAtSelection = function showDragHandleAtSelection(api) {
2
+ return function (state, _, view) {
3
+ var rootPos = state.selection.$from.before(1);
4
+ var dom = view === null || view === void 0 ? void 0 : view.domAtPos(rootPos, 0);
5
+ var rootNode = dom === null || dom === void 0 ? void 0 : dom.node.childNodes[dom === null || dom === void 0 ? void 0 : dom.offset];
6
+ if (rootNode) {
7
+ var anchorName = rootNode.getAttribute('data-drag-handler-anchor-name');
8
+ var nodeType = rootNode.getAttribute('data-drag-handler-node-type');
9
+ if (api && anchorName && nodeType) {
10
+ api.core.actions.execute(api.blockControls.commands.showDragHandleAt(rootPos, anchorName, nodeType, {
11
+ isFocused: true
12
+ }));
13
+ return true;
14
+ }
15
+ }
16
+ return false;
17
+ };
18
+ };
@@ -51,14 +51,15 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
51
51
  return tr;
52
52
  };
53
53
  },
54
- showDragHandleAt: function showDragHandleAt(pos, anchorName, nodeType) {
54
+ showDragHandleAt: function showDragHandleAt(pos, anchorName, nodeType, handleOptions) {
55
55
  return function (_ref4) {
56
56
  var tr = _ref4.tr;
57
57
  tr.setMeta(key, {
58
58
  activeNode: {
59
59
  pos: pos,
60
60
  anchorName: anchorName,
61
- nodeType: nodeType
61
+ nodeType: nodeType,
62
+ handleOptions: handleOptions
62
63
  }
63
64
  });
64
65
  return tr;
@@ -129,13 +129,16 @@ export var mouseMoveWrapperDecorations = function mouseMoveWrapperDecorations(ne
129
129
  });
130
130
  return decs;
131
131
  };
132
- export var dragHandleDecoration = function dragHandleDecoration(pos, anchorName, nodeType, api, getIntl) {
132
+ export var dragHandleDecoration = function dragHandleDecoration(api, getIntl, pos, anchorName, nodeType, handleOptions) {
133
133
  return Decoration.widget(pos, function (view, getPos) {
134
134
  var element = document.createElement('div');
135
135
  // Need to set it to inline to avoid text being split when merging two paragraphs
136
136
  element.style.display = 'inline';
137
137
  element.setAttribute('data-testid', 'block-ctrl-decorator-widget');
138
138
  element.setAttribute('data-blocks-drag-handle-container', 'true');
139
+ if (fg('platform_editor_element_drag_and_drop_ed_23896')) {
140
+ unmountDecorations('data-blocks-drag-handle-container');
141
+ }
139
142
  if (fg('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2')) {
140
143
  // There are times when global clear: "both" styles are applied to this decoration causing jumpiness
141
144
  // due to margins applied to other nodes eg. Headings
@@ -148,14 +151,17 @@ export var dragHandleDecoration = function dragHandleDecoration(pos, anchorName,
148
151
  api: api,
149
152
  getPos: getPos,
150
153
  anchorName: anchorName,
151
- nodeType: nodeType
154
+ nodeType: nodeType,
155
+ handleOptions: handleOptions
152
156
  })), element);
153
157
  return element;
154
158
  }, {
155
159
  side: -1,
156
160
  id: 'drag-handle',
157
161
  destroy: function destroy(node) {
158
- ReactDOM.unmountComponentAtNode(node);
162
+ if (!fg('platform_editor_element_drag_and_drop_ed_23896')) {
163
+ ReactDOM.unmountComponentAtNode(node);
164
+ }
159
165
  }
160
166
  });
161
167
  };
@@ -0,0 +1,18 @@
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
+ var keymapList = {};
7
+ if (api && fg('platform_editor_element_drag_and_drop_ed_23873')) {
8
+ bindKeymapWithCommand(showElementDragHandle.common, function (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 var boundKeydownHandler = function boundKeydownHandler(api) {
17
+ return keydownHandler(keymapList(api));
18
+ };
@@ -12,6 +12,7 @@ import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
12
12
  import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
13
13
  import { dragHandleDecoration, dropTargetDecorations, emptyParagraphNodeDecorations, mouseMoveWrapperDecorations, nodeDecorations } from './decorations';
14
14
  import { handleMouseOver } from './handle-mouse-over';
15
+ import { boundKeydownHandler } from './keymap';
15
16
  export var key = new PluginKey('blockControls');
16
17
  var destroyFn = function destroyFn(api) {
17
18
  var scrollable = document.querySelector('.fabric-editor-popup-scroll-parent');
@@ -85,7 +86,7 @@ export var createPlugin = function createPlugin(api, getIntl) {
85
86
  return initialState;
86
87
  },
87
88
  apply: function apply(tr, currentState, oldState, newState) {
88
- var _meta$activeNode, _meta$activeNode2, _meta$isDragging, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging;
89
+ var _meta$activeNode, _meta$activeNode$hand, _meta$activeNode2, _meta$isDragging, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging;
89
90
  if (initialState.isDocSizeLimitEnabled === null) {
90
91
  if (fg('platform.editor.elements.drag-and-drop-doc-size-limit_7k4vq')) {
91
92
  initialState.isDocSizeLimitEnabled = true;
@@ -118,9 +119,15 @@ export var createPlugin = function createPlugin(api, getIntl) {
118
119
  var resizerMeta = tr.getMeta('is-resizer-resizing');
119
120
  isResizerResizing = resizerMeta !== null && resizerMeta !== void 0 ? resizerMeta : isResizerResizing;
120
121
  var nodeCountChanged = oldState.doc.childCount !== newState.doc.childCount;
122
+ var shouldRemoveHandle = true;
123
+ if (fg('platform_editor_elements_drag_and_drop_ed_24000')) {
124
+ shouldRemoveHandle = !tr.getMeta('isRemote');
125
+ }
121
126
 
122
- // During resize, remove the drag handle widget
123
- if (isResizerResizing || nodeCountChanged || meta !== null && meta !== void 0 && meta.nodeMoved) {
127
+ // During resize, remove the drag handle widget so its dom positioning doesn't need to be maintained
128
+ // Also remove the handle when the node is moved or the node count changes. This helps prevent incorrect positioning
129
+ // Don't remove the handle if remote changes are changing the node count, its prosemirror position can be mapped instead
130
+ if (isResizerResizing || nodeCountChanged && shouldRemoveHandle || meta !== null && meta !== void 0 && meta.nodeMoved) {
124
131
  var oldHandle = decorations.find().filter(function (_ref5) {
125
132
  var spec = _ref5.spec;
126
133
  return spec.id === 'drag-handle';
@@ -156,7 +163,15 @@ export var createPlugin = function createPlugin(api, getIntl) {
156
163
 
157
164
  // Draw node and mouseWrapper decorations at top level node if decorations is empty, editor height changes or node is moved
158
165
  if (redrawDecorations && !isResizerResizing && api) {
159
- decorations = DecorationSet.create(newState.doc, []);
166
+ if (fg('platform_editor_elements_drag_and_drop_ed_24000')) {
167
+ var oldNodeDecs = decorations.find().filter(function (_ref8) {
168
+ var spec = _ref8.spec;
169
+ return spec.type !== 'drop-target-decoration';
170
+ });
171
+ decorations = decorations.remove(oldNodeDecs);
172
+ } else {
173
+ decorations = DecorationSet.create(newState.doc, []);
174
+ }
160
175
  var nodeDecs = nodeDecorations(newState);
161
176
  if (fg('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2')) {
162
177
  decorations = decorations.add(newState.doc, _toConsumableArray(nodeDecs));
@@ -173,7 +188,9 @@ export var createPlugin = function createPlugin(api, getIntl) {
173
188
 
174
189
  // When a node type changed to be nested inside another node, the position of the active node is off by 1
175
190
  // This is a workaround to fix the position of the active node when it is nested
176
- if (mappedPosisiton === prevMappedPos + 1) {
191
+
192
+ var shouldUpdateNestedPosition = fg('platform_editor_element_drag_and_drop_ed_24049') ? tr.docChanged && !nodeCountChanged : true;
193
+ if (shouldUpdateNestedPosition && mappedPosisiton === prevMappedPos + 1) {
177
194
  mappedPosisiton = prevMappedPos;
178
195
  }
179
196
  var newActiveNode = tr.doc.nodeAt(mappedPosisiton);
@@ -188,31 +205,31 @@ export var createPlugin = function createPlugin(api, getIntl) {
188
205
  anchorName: anchorName
189
206
  };
190
207
  }
191
- var draghandleDec = dragHandleDecoration(activeNode.pos, anchorName, nodeType, api, getIntl);
208
+ var draghandleDec = dragHandleDecoration(api, getIntl, activeNode.pos, anchorName, nodeType);
192
209
  decorations = decorations.add(newState.doc, [draghandleDec]);
193
210
  }
194
211
  }
195
212
 
196
213
  // Remove previous drag handle widget and draw new drag handle widget when activeNode changes
197
- 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) {
198
- var _oldHandle = decorations.find().filter(function (_ref8) {
199
- var spec = _ref8.spec;
214
+ 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)) {
215
+ var _oldHandle = decorations.find().filter(function (_ref9) {
216
+ var spec = _ref9.spec;
200
217
  return spec.id === 'drag-handle';
201
218
  });
202
219
  decorations = decorations.remove(_oldHandle);
203
- var decs = dragHandleDecoration(meta.activeNode.pos, meta.activeNode.anchorName, meta.activeNode.nodeType, api, getIntl);
220
+ var decs = dragHandleDecoration(api, getIntl, meta.activeNode.pos, meta.activeNode.anchorName, meta.activeNode.nodeType, meta.activeNode.handleOptions);
204
221
  decorations = decorations.add(newState.doc, [decs]);
205
222
  }
206
223
  if (fg('platform.editor.elements.drag-and-drop-ed-23816')) {
207
224
  var _activeNodeWithNewNod;
208
225
  // Remove previous drag handle widget and draw new drag handle widget when node type changes
209
226
  if (activeNodeWithNewNodeType && ((_activeNodeWithNewNod = activeNodeWithNewNodeType) === null || _activeNodeWithNewNod === void 0 ? void 0 : _activeNodeWithNewNod.nodeType) !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.nodeType) && api) {
210
- var _oldHandle2 = decorations.find().filter(function (_ref9) {
211
- var spec = _ref9.spec;
227
+ var _oldHandle2 = decorations.find().filter(function (_ref10) {
228
+ var spec = _ref10.spec;
212
229
  return spec.id === 'drag-handle';
213
230
  });
214
231
  decorations = decorations.remove(_oldHandle2);
215
- var _decs = dragHandleDecoration(activeNodeWithNewNodeType.pos, activeNodeWithNewNodeType.anchorName, activeNodeWithNewNodeType.nodeType, api, getIntl);
232
+ var _decs = dragHandleDecoration(api, getIntl, activeNodeWithNewNodeType.pos, activeNodeWithNewNodeType.anchorName, activeNodeWithNewNodeType.nodeType);
216
233
  decorations = decorations.add(newState.doc, [_decs]);
217
234
  }
218
235
  }
@@ -228,8 +245,8 @@ export var createPlugin = function createPlugin(api, getIntl) {
228
245
 
229
246
  // Remove drop target decoration when dragging stops
230
247
  if ((meta === null || meta === void 0 ? void 0 : meta.isDragging) === false && !tr.docChanged) {
231
- var dropTargetDecs = decorations.find().filter(function (_ref10) {
232
- var spec = _ref10.spec;
248
+ var dropTargetDecs = decorations.find().filter(function (_ref11) {
249
+ var spec = _ref11.spec;
233
250
  return spec.type === 'drop-target-decoration';
234
251
  });
235
252
  decorations = decorations.remove(dropTargetDecs);
@@ -237,9 +254,9 @@ export var createPlugin = function createPlugin(api, getIntl) {
237
254
 
238
255
  // Map drop target decoration positions when the document changes
239
256
  if (tr.docChanged && isDragging) {
240
- decorationState = decorationState.map(function (_ref11) {
241
- var index = _ref11.index,
242
- pos = _ref11.pos;
257
+ decorationState = decorationState.map(function (_ref12) {
258
+ var index = _ref12.index,
259
+ pos = _ref12.pos;
243
260
  return {
244
261
  index: index,
245
262
  pos: tr.mapping.map(pos)
@@ -252,8 +269,8 @@ export var createPlugin = function createPlugin(api, getIntl) {
252
269
  decorations = decorations.map(tr.mapping, tr.doc);
253
270
  }
254
271
  var isEmptyDoc = newState.doc.childCount === 1 && newState.doc.nodeSize <= 4;
255
- var hasNodeDecoration = decorations.find().some(function (_ref12) {
256
- var spec = _ref12.spec;
272
+ var hasNodeDecoration = decorations.find().some(function (_ref13) {
273
+ var spec = _ref13.spec;
257
274
  return spec.type === 'node-decoration';
258
275
  });
259
276
  if (!hasNodeDecoration && isEmptyDoc) {
@@ -372,6 +389,15 @@ export var createPlugin = function createPlugin(api, getIntl) {
372
389
  return true;
373
390
  }
374
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
+ }
375
401
  return false;
376
402
  }
377
403
  }
@@ -384,7 +410,8 @@ export var createPlugin = function createPlugin(api, getIntl) {
384
410
  if (!fg('platform.editor.elements.drag-and-drop-remove-wrapper_fyqr2')) {
385
411
  // Use ResizeObserver to observe height changes
386
412
  resizeObserverHeight = new ResizeObserver(rafSchedule(function (entries) {
387
- var editorHeight = entries[0].contentBoxSize[0].blockSize;
413
+ var _entries$;
414
+ var editorHeight = (_entries$ = entries[0]) === null || _entries$ === void 0 || (_entries$ = _entries$.contentBoxSize[0]) === null || _entries$ === void 0 ? void 0 : _entries$.blockSize;
388
415
 
389
416
  // Update the plugin state when the height changes
390
417
  var pluginState = key.getState(editorView.state);
@@ -394,7 +421,7 @@ export var createPlugin = function createPlugin(api, getIntl) {
394
421
  if ((pluginState === null || pluginState === void 0 ? void 0 : pluginState.isResizerResizing) !== isResizerResizing) {
395
422
  transaction.setMeta('is-resizer-resizing', isResizerResizing);
396
423
  }
397
- if (!isResizerResizing) {
424
+ if (!isResizerResizing && editorHeight) {
398
425
  transaction.setMeta(key, {
399
426
  editorHeight: editorHeight
400
427
  });