@atlaskit/editor-plugin-block-controls 2.9.0 → 2.10.1

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cjs/commands/move-to-layout.js +16 -1
  3. package/dist/cjs/pm-plugins/decorations-anchor.js +99 -0
  4. package/dist/cjs/pm-plugins/decorations-common.js +49 -0
  5. package/dist/cjs/pm-plugins/decorations-drag-handle.js +88 -0
  6. package/dist/cjs/pm-plugins/{decorations.js → decorations-drop-target.js} +11 -208
  7. package/dist/cjs/pm-plugins/main.js +21 -19
  8. package/dist/cjs/ui/drop-target-v2.js +3 -3
  9. package/dist/cjs/ui/inline-drop-target.js +79 -20
  10. package/dist/cjs/utils/check-media-layout.js +14 -0
  11. package/dist/cjs/utils/inline-drop-target.js +4 -0
  12. package/dist/es2019/commands/move-to-layout.js +16 -1
  13. package/dist/es2019/pm-plugins/decorations-anchor.js +91 -0
  14. package/dist/es2019/pm-plugins/decorations-common.js +31 -0
  15. package/dist/es2019/pm-plugins/decorations-drag-handle.js +79 -0
  16. package/dist/es2019/pm-plugins/{decorations.js → decorations-drop-target.js} +6 -192
  17. package/dist/es2019/pm-plugins/main.js +3 -1
  18. package/dist/es2019/ui/drop-target-v2.js +1 -1
  19. package/dist/es2019/ui/inline-drop-target.js +77 -18
  20. package/dist/es2019/utils/check-media-layout.js +8 -0
  21. package/dist/es2019/utils/inline-drop-target.js +4 -0
  22. package/dist/esm/commands/move-to-layout.js +16 -1
  23. package/dist/esm/pm-plugins/decorations-anchor.js +92 -0
  24. package/dist/esm/pm-plugins/decorations-common.js +42 -0
  25. package/dist/esm/pm-plugins/decorations-drag-handle.js +81 -0
  26. package/dist/esm/pm-plugins/{decorations.js → decorations-drop-target.js} +6 -203
  27. package/dist/esm/pm-plugins/main.js +3 -1
  28. package/dist/esm/ui/drop-target-v2.js +1 -1
  29. package/dist/esm/ui/inline-drop-target.js +77 -18
  30. package/dist/esm/utils/check-media-layout.js +8 -0
  31. package/dist/esm/utils/inline-drop-target.js +4 -0
  32. package/dist/types/pm-plugins/decorations-anchor.d.ts +13 -0
  33. package/dist/types/pm-plugins/decorations-common.d.ts +7 -0
  34. package/dist/types/pm-plugins/decorations-drag-handle.d.ts +7 -0
  35. package/dist/types/pm-plugins/decorations-drop-target.d.ts +17 -0
  36. package/dist/types/ui/inline-drop-target.d.ts +6 -1
  37. package/dist/types/utils/check-media-layout.d.ts +2 -0
  38. package/dist/types-ts4.5/pm-plugins/decorations-anchor.d.ts +13 -0
  39. package/dist/types-ts4.5/pm-plugins/decorations-common.d.ts +7 -0
  40. package/dist/types-ts4.5/pm-plugins/decorations-drag-handle.d.ts +7 -0
  41. package/dist/types-ts4.5/pm-plugins/decorations-drop-target.d.ts +17 -0
  42. package/dist/types-ts4.5/ui/inline-drop-target.d.ts +6 -1
  43. package/dist/types-ts4.5/utils/check-media-layout.d.ts +2 -0
  44. package/package.json +6 -6
  45. package/dist/types/pm-plugins/decorations.d.ts +0 -35
  46. package/dist/types-ts4.5/pm-plugins/decorations.d.ts +0 -35
@@ -1,29 +1,23 @@
1
- import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
1
  import { createElement } from 'react';
3
- import { bind } from 'bind-event-listener';
4
2
  import ReactDOM from 'react-dom';
5
- import uuid from 'uuid';
6
3
  import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
7
4
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
8
5
  import { fg } from '@atlaskit/platform-feature-flags';
9
6
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
10
7
  import { nodeMargins } from '../ui/consts';
11
- import { DragHandle } from '../ui/drag-handle';
12
8
  import { DropTarget } from '../ui/drop-target';
13
9
  import { DropTargetV2, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET } from '../ui/drop-target-v2';
14
10
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
15
11
  import { canMoveNodeToIndex } from '../utils/validation';
12
+ import { getNestedDepth, TYPE_DROP_TARGET_DEC, unmountDecorations } from './decorations-common';
16
13
  const IGNORE_NODES = ['tableCell', 'tableHeader', 'tableRow', 'layoutColumn', 'listItem', 'caption'];
17
- const IGNORE_NODE_DESCENDANTS = ['listItem', 'taskList', 'decisionList', 'mediaSingle'];
18
14
  const PARENT_WITH_END_DROP_TARGET = ['tableCell', 'tableHeader', 'panel', 'layoutColumn', 'expand', 'nestedExpand', 'bodiedExtension'];
19
15
  const DISABLE_CHILD_DROP_TARGET = ['orderedList', 'bulletList'];
20
- export const TYPE_DROP_TARGET_DEC = 'drop-target-decoration';
21
- export const TYPE_HANDLE_DEC = 'drag-handle';
22
- export const TYPE_NODE_DEC = 'node-decoration';
23
- const getNestedDepth = () => editorExperiment('nested-dnd', true) ? 100 : 0;
24
- export const getNodeAnchor = node => {
25
- const handleId = ObjHash.getForNode(node);
26
- return `--node-anchor-${node.type.name}-${handleId}`;
16
+ const shouldDescend = node => {
17
+ if (fg('platform_editor_drag_and_drop_target_v2')) {
18
+ return !['mediaSingle', 'paragraph', 'heading'].includes(node.type.name);
19
+ }
20
+ return true;
27
21
  };
28
22
  const getNodeMargins = node => {
29
23
  if (!node) {
@@ -68,12 +62,6 @@ const getGapAndOffset = (prevNode, nextNode, parentNode) => {
68
62
  offset
69
63
  };
70
64
  };
71
- const shouldDescend = node => {
72
- if (fg('platform_editor_drag_and_drop_target_v2')) {
73
- return !['mediaSingle', 'paragraph', 'heading'].includes(node.type.name);
74
- }
75
- return true;
76
- };
77
65
 
78
66
  /**
79
67
  * Find drop target decorations in the pos range between from and to
@@ -85,37 +73,6 @@ const shouldDescend = node => {
85
73
  export const findDropTargetDecs = (decorations, from, to) => {
86
74
  return decorations.find(from, to, spec => spec.type === TYPE_DROP_TARGET_DEC);
87
75
  };
88
- export const findHandleDec = (decorations, from, to) => {
89
- return decorations.find(from, to, spec => spec.type === TYPE_HANDLE_DEC);
90
- };
91
-
92
- /**
93
- * Find node decorations in the pos range between from and to (non-inclusive)
94
- * @param decorations
95
- * @param from
96
- * @param to
97
- * @returns
98
- */
99
- export const findNodeDecs = (decorations, from, to) => {
100
- let newfrom = from;
101
- let newTo = to;
102
-
103
- // make it non-inclusive
104
- if (newfrom !== undefined) {
105
- newfrom++;
106
- }
107
-
108
- // make it non-inclusive
109
- if (newTo !== undefined) {
110
- newTo--;
111
- }
112
-
113
- // return empty array if range reversed
114
- if (newfrom !== undefined && newTo !== undefined && newfrom > newTo) {
115
- return new Array();
116
- }
117
- return decorations.find(newfrom, newTo, spec => spec.type === TYPE_NODE_DEC);
118
- };
119
76
  export const createDropTargetDecoration = (pos, props, side, anchorRectCache) => {
120
77
  return Decoration.widget(pos, (_, getPos) => {
121
78
  const element = document.createElement('div');
@@ -244,147 +201,4 @@ export const dropTargetDecorations = (newState, api, formatMessage, activeNode,
244
201
  }, undefined, anchorRectCache));
245
202
  }
246
203
  return decs;
247
- };
248
- export const emptyParagraphNodeDecorations = () => {
249
- const anchorName = `--node-anchor-paragraph-0`;
250
- const style = `anchor-name: ${anchorName}; margin-top: 0px;`;
251
- return Decoration.node(0, 2, {
252
- style,
253
- ['data-drag-handler-anchor-name']: anchorName
254
- }, {
255
- type: TYPE_NODE_DEC
256
- });
257
- };
258
- class ObjHash {
259
- static getForNode(node) {
260
- if (this.caching.has(node)) {
261
- return this.caching.get(node);
262
- }
263
- const uniqueId = uuid();
264
- this.caching.set(node, uniqueId);
265
- return uniqueId;
266
- }
267
- }
268
- _defineProperty(ObjHash, "caching", new WeakMap());
269
- const shouldIgnoreNode = node => {
270
- if ('mediaSingle' === node.type.name && fg('platform_editor_element_dnd_nested_fix_patch_1')) {
271
- if (['wrap-right', 'wrap-left'].includes(node.attrs.layout)) {
272
- return true;
273
- }
274
- }
275
- return IGNORE_NODES.includes(node.type.name);
276
- };
277
- export const shouldDescendIntoNode = node => {
278
- // Optimisation to avoid drawing node decorations for empty table cells
279
- if (['tableCell', 'tableHeader'].includes(node.type.name) && !editorExperiment('table-nested-dnd', true) && fg('platform_editor_element_dnd_nested_fix_patch_3')) {
280
- var _node$firstChild;
281
- if (node.childCount === 1 && ((_node$firstChild = node.firstChild) === null || _node$firstChild === void 0 ? void 0 : _node$firstChild.type.name) === 'paragraph') {
282
- return false;
283
- }
284
- }
285
- return !IGNORE_NODE_DESCENDANTS.includes(node.type.name);
286
- };
287
- export const nodeDecorations = (newState, from, to) => {
288
- const decs = [];
289
- const docFrom = from === undefined || from < 0 ? 0 : from;
290
- const docTo = to === undefined || to > newState.doc.nodeSize - 2 ? newState.doc.nodeSize - 2 : to;
291
- newState.doc.nodesBetween(docFrom, docTo, (node, pos, _parent, index) => {
292
- let depth = 0;
293
- let anchorName;
294
- const shouldDescend = shouldDescendIntoNode(node);
295
- const handleId = ObjHash.getForNode(node);
296
- anchorName = `--node-anchor-${node.type.name}-${handleId}`;
297
- if (editorExperiment('nested-dnd', true)) {
298
- var _anchorName;
299
- // Doesn't descend into a node
300
- if (node.isInline) {
301
- return false;
302
- }
303
- if (shouldIgnoreNode(node)) {
304
- return shouldDescend; //skip over, don't consider it a valid depth
305
- }
306
- depth = newState.doc.resolve(pos).depth;
307
- anchorName = (_anchorName = anchorName) !== null && _anchorName !== void 0 ? _anchorName : `--node-anchor-${node.type.name}-${pos}`;
308
- } else {
309
- var _anchorName2;
310
- anchorName = (_anchorName2 = anchorName) !== null && _anchorName2 !== void 0 ? _anchorName2 : `--node-anchor-${node.type.name}-${index}`;
311
- }
312
- decs.push(Decoration.node(pos, pos + node.nodeSize, {
313
- style: `anchor-name: ${anchorName}; ${pos === 0 ? 'margin-top: 0px;' : ''}; position: relative; z-index: 1;`,
314
- ['data-drag-handler-anchor-name']: anchorName,
315
- ['data-drag-handler-node-type']: node.type.name,
316
- ['data-drag-handler-anchor-depth']: `${depth}`
317
- }, {
318
- type: TYPE_NODE_DEC,
319
- anchorName,
320
- nodeType: node.type.name
321
- }));
322
- return shouldDescend && depth < getNestedDepth();
323
- });
324
- return decs;
325
- };
326
- export const dragHandleDecoration = (api, formatMessage, pos, anchorName, nodeType, handleOptions) => {
327
- unmountDecorations('data-blocks-drag-handle-container');
328
- let unbind;
329
- return Decoration.widget(pos, (view, getPos) => {
330
- const element = document.createElement('span');
331
- // Need to set it to inline to avoid text being split when merging two paragraphs
332
- // platform_editor_element_dnd_nested_fix_patch_2 -> inline decoration causes focus issues when refocusing Editor into first line
333
- element.style.display = fg('platform_editor_element_dnd_nested_fix_patch_2') ? 'block' : 'inline';
334
- element.setAttribute('data-testid', 'block-ctrl-decorator-widget');
335
- element.setAttribute('data-blocks-drag-handle-container', 'true');
336
- let isTopLevelNode = true;
337
- if (editorExperiment('nested-dnd', true)) {
338
- const newPos = fg('platform_editor_element_dnd_nested_fix_patch_3') ? getPos() : pos;
339
- if (typeof newPos === 'number') {
340
- const $pos = view.state.doc.resolve(newPos);
341
- isTopLevelNode = ($pos === null || $pos === void 0 ? void 0 : $pos.parent.type.name) === 'doc';
342
- }
343
- /*
344
- * We disable mouseover event to fix flickering issue on hover
345
- * However, the tooltip for nested drag handle is no long working.
346
- */
347
- if (newPos === undefined || !isTopLevelNode) {
348
- // This will also hide the tooltip.
349
- unbind = bind(element, {
350
- type: 'mouseover',
351
- listener: e => {
352
- e.stopPropagation();
353
- }
354
- });
355
- }
356
- }
357
-
358
- // There are times when global clear: "both" styles are applied to this decoration causing jumpiness
359
- // due to margins applied to other nodes eg. Headings
360
- element.style.clear = 'unset';
361
- ReactDOM.render( /*#__PURE__*/createElement(DragHandle, {
362
- view,
363
- api,
364
- formatMessage,
365
- getPos,
366
- anchorName,
367
- nodeType,
368
- handleOptions,
369
- isTopLevelNode
370
- }), element);
371
- return element;
372
- }, {
373
- side: -1,
374
- type: TYPE_HANDLE_DEC,
375
- testid: `${TYPE_HANDLE_DEC}-${uuid()}`,
376
- destroy: () => {
377
- if (editorExperiment('nested-dnd', true)) {
378
- unbind && unbind();
379
- }
380
- }
381
- });
382
- };
383
- const unmountDecorations = selector => {
384
- // Removing decorations manually instead of using native destroy function in prosemirror API
385
- // as it was more responsive and causes less re-rendering
386
- const decorationsToRemove = document.querySelectorAll(`[${selector}="true"]`);
387
- decorationsToRemove.forEach(el => {
388
- ReactDOM.unmountComponentAtNode(el);
389
- });
390
204
  };
@@ -14,7 +14,9 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
14
14
  import { AnchorRectCache, isAnchorSupported } from '../utils/anchor-utils';
15
15
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
16
16
  import { getTrMetadata } from '../utils/transactions';
17
- import { dragHandleDecoration, dropTargetDecorations, emptyParagraphNodeDecorations, findDropTargetDecs, findHandleDec, findNodeDecs, nodeDecorations } from './decorations';
17
+ import { findNodeDecs, nodeDecorations } from './decorations-anchor';
18
+ import { dragHandleDecoration, emptyParagraphNodeDecorations, findHandleDec } from './decorations-drag-handle';
19
+ import { dropTargetDecorations, findDropTargetDecs } from './decorations-drop-target';
18
20
  import { handleMouseOver } from './handle-mouse-over';
19
21
  import { boundKeydownHandler } from './keymap';
20
22
  export const key = new PluginKey('blockControls');
@@ -12,7 +12,7 @@ import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indi
12
12
  import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
13
13
  import { layers } from '@atlaskit/theme/constants';
14
14
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
15
- import { getNodeAnchor } from '../pm-plugins/decorations';
15
+ import { getNodeAnchor } from '../pm-plugins/decorations-common';
16
16
  import { isAnchorSupported } from '../utils/anchor-utils';
17
17
  import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
18
18
  import { shouldAllowInlineDropTarget } from '../utils/inline-drop-target';
@@ -11,19 +11,17 @@ import { css, jsx } from '@emotion/react';
11
11
  import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
12
12
  import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box';
13
13
  import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
14
- import { getNodeAnchor } from '../pm-plugins/decorations';
14
+ import { getNodeAnchor } from '../pm-plugins/decorations-common';
15
15
  import { isAnchorSupported } from '../utils/anchor-utils';
16
+ import { isBlocksDragTargetDebug } from '../utils/drag-target-debug';
16
17
  const dropTargetCommonStyle = css({
17
18
  position: 'absolute',
18
19
  display: 'block'
19
20
  });
20
- const hideDropTargetStyle = css({
21
- display: 'none'
22
- });
23
21
  const hoverZoneCommonStyle = css({
24
22
  position: 'absolute',
25
- // same value as block hover zone
26
- zIndex: 110
23
+ // above the top and bottom drop zone as block hover zone
24
+ zIndex: 120
27
25
  });
28
26
 
29
27
  // gap between node boundary and drop indicator/drop zone
@@ -31,6 +29,60 @@ const GAP = 4;
31
29
  const HOVER_ZONE_WIDTH_OFFSET = 40;
32
30
  const HOVER_ZONE_HEIGHT_OFFSET = 10;
33
31
  const HOVER_ZONE_DEFAULT_WIDTH = 40;
32
+ const getDropTargetPositionOverride = (node, editorWidth) => {
33
+ if (!node || !editorWidth) {
34
+ return {
35
+ left: 0,
36
+ right: 0
37
+ };
38
+ }
39
+ const getOffsets = nodeWidth => {
40
+ const offset = (editorWidth - nodeWidth) / 2;
41
+ return {
42
+ left: offset,
43
+ right: offset
44
+ };
45
+ };
46
+ if ((node === null || node === void 0 ? void 0 : node.type.name) === 'table' && node.attrs.width) {
47
+ return getOffsets(node.attrs.width);
48
+ }
49
+
50
+ // media single 🤦
51
+ if ((node === null || node === void 0 ? void 0 : node.type.name) === 'mediaSingle') {
52
+ let mediaNodeWidth = 0;
53
+ if (node.attrs.width) {
54
+ if (node.attrs.widthType === 'pixel') {
55
+ mediaNodeWidth = node.attrs.width;
56
+ } else if (editorWidth) {
57
+ mediaNodeWidth = node.attrs.width / 100 * editorWidth;
58
+ }
59
+ } else {
60
+ // use media width
61
+ const mediaNode = node.firstChild;
62
+ if (mediaNode && mediaNode.attrs.width) {
63
+ mediaNodeWidth = mediaNode.attrs.width;
64
+ }
65
+ }
66
+ if (mediaNodeWidth) {
67
+ if (node.attrs.layout === 'align-start') {
68
+ return {
69
+ left: 0,
70
+ right: editorWidth - mediaNodeWidth
71
+ };
72
+ } else if (node.attrs.layout === 'align-end') {
73
+ return {
74
+ left: editorWidth - mediaNodeWidth,
75
+ right: 0
76
+ };
77
+ }
78
+ return getOffsets(mediaNodeWidth);
79
+ }
80
+ }
81
+ return {
82
+ left: 0,
83
+ right: 0
84
+ };
85
+ };
34
86
  export const InlineDropTarget = ({
35
87
  api,
36
88
  nextNode,
@@ -49,22 +101,25 @@ export const InlineDropTarget = ({
49
101
  const handleDragLeave = useCallback(() => {
50
102
  setIsDraggedOver(false);
51
103
  }, []);
104
+ const offsets = useMemo(() => {
105
+ return getDropTargetPositionOverride(nextNode, widthState === null || widthState === void 0 ? void 0 : widthState.lineLength);
106
+ }, [nextNode, widthState]);
52
107
  const dropTargetRectStyle = useMemo(() => {
53
108
  if (isAnchorSupported()) {
54
109
  return css({
55
110
  height: `calc(anchor-size(${anchorName} height))`,
56
111
  positionAnchor: anchorName,
57
- left: position === 'left' ? `calc(anchor(left) - ${GAP}px)` : `calc(anchor(right) + ${GAP}px)`,
112
+ left: position === 'left' ? `calc(anchor(left) - ${GAP - offsets.left}px)` : `calc(anchor(right) + ${GAP - offsets.right}px)`,
58
113
  top: `calc(anchor(top))`
59
114
  });
60
115
  }
61
116
  const nodeRect = anchorRectCache === null || anchorRectCache === void 0 ? void 0 : anchorRectCache.getRect(anchorName);
62
117
  return css({
63
118
  height: `calc(${(nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.height) || 0}px)`,
64
- left: position === 'left' ? `${((nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.left) || 0) - GAP}px` : `${((nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.right) || 0) + GAP}px`,
119
+ left: position === 'left' ? `${((nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.left) || 0) - GAP + offsets.left}px` : `${((nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.right) || 0) + GAP - offsets.right}px`,
65
120
  top: `${(nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.top) || 0}px`
66
121
  });
67
- }, [anchorName, anchorRectCache, position]);
122
+ }, [anchorName, anchorRectCache, offsets.left, offsets.right, position]);
68
123
  const onDrop = useCallback(() => {
69
124
  var _api$blockControls;
70
125
  const {
@@ -84,8 +139,8 @@ export const InlineDropTarget = ({
84
139
  }, [api, getPos, position]);
85
140
  return jsx(Fragment, null, jsx("div", {
86
141
  "data-test-id": `block-ctrl-drop-target-${position}`,
87
- css: [dropTargetCommonStyle, dropTargetRectStyle, !isDraggedOver && hideDropTargetStyle]
88
- }, jsx(DropIndicator, {
142
+ css: [dropTargetCommonStyle, dropTargetRectStyle]
143
+ }, (isDraggedOver || isBlocksDragTargetDebug()) && jsx(DropIndicator, {
89
144
  edge: position
90
145
  })), jsx(InlineHoverZone, {
91
146
  position: position,
@@ -94,7 +149,8 @@ export const InlineDropTarget = ({
94
149
  anchorRectCache: anchorRectCache,
95
150
  onDragEnter: handleDragEnter,
96
151
  onDragLeave: handleDragLeave,
97
- onDrop: onDrop
152
+ onDrop: onDrop,
153
+ offsets: offsets
98
154
  }));
99
155
  };
100
156
  export const InlineHoverZone = ({
@@ -102,6 +158,7 @@ export const InlineHoverZone = ({
102
158
  editorWidthState,
103
159
  anchorRectCache,
104
160
  position,
161
+ offsets,
105
162
  onDragEnter,
106
163
  onDragLeave,
107
164
  onDrop
@@ -122,27 +179,29 @@ export const InlineHoverZone = ({
122
179
  }
123
180
  }, [onDragEnter, onDragLeave, onDrop]);
124
181
  const inlineHoverZoneRectStyle = useMemo(() => {
182
+ const offset = offsets[position];
125
183
  if (isAnchorSupported()) {
126
184
  return css({
127
185
  positionAnchor: anchorName,
128
- left: position === 'left' ? 'unset' : `calc(anchor(right) + ${GAP}px)`,
129
- right: position === 'left' ? `calc(anchor(left) + ${GAP}px)` : 'unset',
186
+ left: position === 'left' ? 'unset' : `calc(anchor(right) + ${GAP - offset}px)`,
187
+ right: position === 'left' ? `calc(anchor(left) + ${GAP - offset}px)` : 'unset',
130
188
  top: `calc(anchor(top))`,
131
- width: editorWith ? `calc((${editorWith}px - anchor-size(${anchorName} width))/2 - ${HOVER_ZONE_WIDTH_OFFSET}px)` : `${HOVER_ZONE_DEFAULT_WIDTH}px`,
189
+ width: editorWith ? `calc((${editorWith}px - anchor-size(${anchorName} width))/2 - ${HOVER_ZONE_WIDTH_OFFSET}px + ${offset}px)` : `${HOVER_ZONE_DEFAULT_WIDTH}px`,
132
190
  height: `calc(anchor-size(${anchorName} height))`
133
191
  });
134
192
  }
135
193
  const nodeRect = anchorRectCache === null || anchorRectCache === void 0 ? void 0 : anchorRectCache.getRect(anchorName);
136
- const width = editorWith ? (editorWith - ((nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.width) || 0)) / 2 - HOVER_ZONE_WIDTH_OFFSET : HOVER_ZONE_DEFAULT_WIDTH;
194
+ const width = editorWith ? (editorWith - ((nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.width) || 0)) / 2 - HOVER_ZONE_WIDTH_OFFSET + offset : HOVER_ZONE_DEFAULT_WIDTH;
137
195
  return css({
138
- left: position === 'left' ? `${((nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.left) || 0) - width - GAP}px` : `${((nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.right) || 0) + GAP}px`,
196
+ left: position === 'left' ? `${((nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.left) || 0) - width - GAP + offset}px` : `${((nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.right) || 0) + GAP - offset}px`,
139
197
  top: `${(nodeRect === null || nodeRect === void 0 ? void 0 : nodeRect.top) || 0}px`,
140
198
  width: `${width}px`,
141
199
  height: `calc(${(anchorRectCache === null || anchorRectCache === void 0 ? void 0 : anchorRectCache.getHeight(anchorName)) || 0}px - ${HOVER_ZONE_HEIGHT_OFFSET}px)`
142
200
  });
143
- }, [anchorName, anchorRectCache, editorWith, position]);
201
+ }, [anchorName, anchorRectCache, editorWith, offsets, position]);
144
202
  return jsx("div", {
145
203
  ref: ref,
204
+ "data-test-id": `drop-target-hover-zone-${position}`,
146
205
  css: [hoverZoneCommonStyle, inlineHoverZoneRectStyle]
147
206
  });
148
207
  };
@@ -0,0 +1,8 @@
1
+ export const isWrappedMedia = node => {
2
+ if ('mediaSingle' === (node === null || node === void 0 ? void 0 : node.type.name)) {
3
+ if (['wrap-right', 'wrap-left'].includes(node.attrs.layout)) {
4
+ return true;
5
+ }
6
+ }
7
+ return false;
8
+ };
@@ -1,10 +1,14 @@
1
1
  import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
2
2
  import { MAX_LAYOUT_COLUMN_SUPPORTED } from '../consts';
3
3
  import { isPreRelease1 } from './advanced-layouts-flags';
4
+ import { isWrappedMedia } from './check-media-layout';
4
5
  export const shouldAllowInlineDropTarget = (isNested, node) => {
5
6
  if (!isPreRelease1() || isNested) {
6
7
  return false;
7
8
  }
9
+ if (isWrappedMedia(node)) {
10
+ return false;
11
+ }
8
12
  if ((node === null || node === void 0 ? void 0 : node.type.name) === 'layoutSection') {
9
13
  return node.childCount < MAX_LAYOUT_COLUMN_SUPPORTED;
10
14
  }
@@ -1,4 +1,5 @@
1
1
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
+ import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
2
3
  import { MAX_LAYOUT_COLUMN_SUPPORTED } from '../consts';
3
4
  import { DEFAULT_COLUMN_DISTRIBUTIONS } from '../ui/consts';
4
5
  var createNewLayout = function createNewLayout(schema, layoutContents) {
@@ -68,13 +69,25 @@ export var moveToLayout = function moveToLayout(api) {
68
69
  if ($to.nodeAfter.type === layoutSection) {
69
70
  var existingLayoutNode = $to.nodeAfter;
70
71
  if (existingLayoutNode.childCount < MAX_LAYOUT_COLUMN_SUPPORTED) {
72
+ var newColumnWidth = DEFAULT_COLUMN_DISTRIBUTIONS[existingLayoutNode.childCount + 1];
73
+ if (newColumnWidth) {
74
+ existingLayoutNode.content.forEach(function (node, offset) {
75
+ if (node.type === layoutColumn) {
76
+ tr = tr.setNodeAttribute(to + offset + 1, 'width', newColumnWidth);
77
+ }
78
+ });
79
+ }
71
80
  var toPos = position === 'left' ? to + 1 : to + existingLayoutNode.nodeSize - 1;
72
81
  tr = tr.insert(toPos,
73
82
  // resolve again the source node after node updated (remove breakout marks)
74
- layoutColumn.create(null, tr.doc.resolve(from).nodeAfter));
83
+ layoutColumn.create({
84
+ width: newColumnWidth
85
+ }, tr.doc.resolve(from).nodeAfter));
86
+ tr = tr.setSelection(new NodeSelection(tr.doc.resolve(toPos)));
75
87
  var mappedFrom = tr.mapping.map(from);
76
88
  var mappedFromEnd = mappedFrom + fromNode.nodeSize;
77
89
  tr = tr.delete(mappedFrom, mappedFromEnd);
90
+ tr = tr.scrollIntoView();
78
91
  return tr;
79
92
  }
80
93
  return tr;
@@ -91,6 +104,8 @@ export var moveToLayout = function moveToLayout(api) {
91
104
  var mappedTo = tr.mapping.map(to);
92
105
  tr = tr.delete(mappedTo, mappedTo + toNode.nodeSize);
93
106
  tr = tr.insert(mappedTo, newLayout); // insert the content at the new position
107
+ tr = tr.setSelection(new NodeSelection(tr.doc.resolve(mappedTo)));
108
+ tr = tr.scrollIntoView();
94
109
  }
95
110
  return tr;
96
111
  }
@@ -0,0 +1,92 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
4
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
5
+ import { getNestedDepth, getNodeAnchor, TYPE_NODE_DEC } from './decorations-common';
6
+ var IGNORE_NODES = ['tableCell', 'tableHeader', 'tableRow', 'layoutColumn', 'listItem', 'caption'];
7
+ var IGNORE_NODE_DESCENDANTS = ['listItem', 'taskList', 'decisionList', 'mediaSingle'];
8
+ export var shouldDescendIntoNode = function shouldDescendIntoNode(node) {
9
+ // Optimisation to avoid drawing node decorations for empty table cells
10
+ if (['tableCell', 'tableHeader'].includes(node.type.name) && !editorExperiment('table-nested-dnd', true) && fg('platform_editor_element_dnd_nested_fix_patch_3')) {
11
+ var _node$firstChild;
12
+ if (node.childCount === 1 && ((_node$firstChild = node.firstChild) === null || _node$firstChild === void 0 ? void 0 : _node$firstChild.type.name) === 'paragraph') {
13
+ return false;
14
+ }
15
+ }
16
+ return !IGNORE_NODE_DESCENDANTS.includes(node.type.name);
17
+ };
18
+ var shouldIgnoreNode = function shouldIgnoreNode(node) {
19
+ // TODO use isWrappedMedia when clean up the featue flag
20
+ if ('mediaSingle' === node.type.name && fg('platform_editor_element_dnd_nested_fix_patch_1')) {
21
+ if (['wrap-right', 'wrap-left'].includes(node.attrs.layout)) {
22
+ return true;
23
+ }
24
+ }
25
+ return IGNORE_NODES.includes(node.type.name);
26
+ };
27
+
28
+ /**
29
+ * Find node decorations in the pos range between from and to (non-inclusive)
30
+ * @param decorations
31
+ * @param from
32
+ * @param to
33
+ * @returns
34
+ */
35
+ export var findNodeDecs = function findNodeDecs(decorations, from, to) {
36
+ var newfrom = from;
37
+ var newTo = to;
38
+
39
+ // make it non-inclusive
40
+ if (newfrom !== undefined) {
41
+ newfrom++;
42
+ }
43
+
44
+ // make it non-inclusive
45
+ if (newTo !== undefined) {
46
+ newTo--;
47
+ }
48
+
49
+ // return empty array if range reversed
50
+ if (newfrom !== undefined && newTo !== undefined && newfrom > newTo) {
51
+ return new Array();
52
+ }
53
+ return decorations.find(newfrom, newTo, function (spec) {
54
+ return spec.type === TYPE_NODE_DEC;
55
+ });
56
+ };
57
+ export var nodeDecorations = function nodeDecorations(newState, from, to) {
58
+ var decs = [];
59
+ var docFrom = from === undefined || from < 0 ? 0 : from;
60
+ var docTo = to === undefined || to > newState.doc.nodeSize - 2 ? newState.doc.nodeSize - 2 : to;
61
+ newState.doc.nodesBetween(docFrom, docTo, function (node, pos, _parent, index) {
62
+ var _Decoration$node;
63
+ var depth = 0;
64
+ var anchorName;
65
+ var shouldDescend = shouldDescendIntoNode(node);
66
+ anchorName = getNodeAnchor(node);
67
+ if (editorExperiment('nested-dnd', true)) {
68
+ var _anchorName;
69
+ // Doesn't descend into a node
70
+ if (node.isInline) {
71
+ return false;
72
+ }
73
+ if (shouldIgnoreNode(node)) {
74
+ return shouldDescend; //skip over, don't consider it a valid depth
75
+ }
76
+ depth = newState.doc.resolve(pos).depth;
77
+ anchorName = (_anchorName = anchorName) !== null && _anchorName !== void 0 ? _anchorName : "--node-anchor-".concat(node.type.name, "-").concat(pos);
78
+ } else {
79
+ var _anchorName2;
80
+ anchorName = (_anchorName2 = anchorName) !== null && _anchorName2 !== void 0 ? _anchorName2 : "--node-anchor-".concat(node.type.name, "-").concat(index);
81
+ }
82
+ decs.push(Decoration.node(pos, pos + node.nodeSize, (_Decoration$node = {
83
+ style: "anchor-name: ".concat(anchorName, "; ").concat(pos === 0 ? 'margin-top: 0px;' : '', "; position: relative; z-index: 1;")
84
+ }, _defineProperty(_Decoration$node, 'data-drag-handler-anchor-name', anchorName), _defineProperty(_Decoration$node, 'data-drag-handler-node-type', node.type.name), _defineProperty(_Decoration$node, 'data-drag-handler-anchor-depth', "".concat(depth)), _Decoration$node), {
85
+ type: TYPE_NODE_DEC,
86
+ anchorName: anchorName,
87
+ nodeType: node.type.name
88
+ }));
89
+ return shouldDescend && depth < getNestedDepth();
90
+ });
91
+ return decs;
92
+ };
@@ -0,0 +1,42 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
+ import _createClass from "@babel/runtime/helpers/createClass";
3
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
+ import ReactDOM from 'react-dom';
5
+ import uuid from 'uuid';
6
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
7
+ export var TYPE_DROP_TARGET_DEC = 'drop-target-decoration';
8
+ export var TYPE_HANDLE_DEC = 'drag-handle';
9
+ export var TYPE_NODE_DEC = 'node-decoration';
10
+ export var getNestedDepth = function getNestedDepth() {
11
+ return editorExperiment('nested-dnd', true) ? 100 : 0;
12
+ };
13
+ export var getNodeAnchor = function getNodeAnchor(node) {
14
+ var handleId = ObjHash.getForNode(node);
15
+ return "--node-anchor-".concat(node.type.name, "-").concat(handleId);
16
+ };
17
+ var ObjHash = /*#__PURE__*/function () {
18
+ function ObjHash() {
19
+ _classCallCheck(this, ObjHash);
20
+ }
21
+ _createClass(ObjHash, null, [{
22
+ key: "getForNode",
23
+ value: function getForNode(node) {
24
+ if (this.caching.has(node)) {
25
+ return this.caching.get(node);
26
+ }
27
+ var uniqueId = uuid();
28
+ this.caching.set(node, uniqueId);
29
+ return uniqueId;
30
+ }
31
+ }]);
32
+ return ObjHash;
33
+ }();
34
+ _defineProperty(ObjHash, "caching", new WeakMap());
35
+ export var unmountDecorations = function unmountDecorations(selector) {
36
+ // Removing decorations manually instead of using native destroy function in prosemirror API
37
+ // as it was more responsive and causes less re-rendering
38
+ var decorationsToRemove = document.querySelectorAll("[".concat(selector, "=\"true\"]"));
39
+ decorationsToRemove.forEach(function (el) {
40
+ ReactDOM.unmountComponentAtNode(el);
41
+ });
42
+ };