@atlaskit/editor-plugin-block-controls 20.0.2 → 20.1.0

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 (148) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/cjs/blockControlsPlugin.js +53 -17
  3. package/dist/cjs/editor-commands/move-node.js +1 -1
  4. package/dist/cjs/editor-commands/show-drag-handle.js +17 -5
  5. package/dist/cjs/pm-plugins/decorations-anchor.js +3 -2
  6. package/dist/cjs/pm-plugins/decorations-drop-target-active.js +3 -2
  7. package/dist/cjs/pm-plugins/decorations-drop-target.js +3 -2
  8. package/dist/cjs/pm-plugins/decorations-surface-anchor.js +72 -0
  9. package/dist/cjs/pm-plugins/handle-mouse-down.js +2 -1
  10. package/dist/cjs/pm-plugins/handle-mouse-over.js +4 -3
  11. package/dist/cjs/pm-plugins/handle-sparse-mouse-over.js +125 -0
  12. package/dist/cjs/pm-plugins/interaction-tracking/pm-plugin.js +1 -1
  13. package/dist/cjs/pm-plugins/main.js +68 -56
  14. package/dist/cjs/pm-plugins/sparse-surfaces.js +49 -0
  15. package/dist/cjs/pm-plugins/utils/drag-handle-positions.js +1 -1
  16. package/dist/cjs/pm-plugins/utils/sparse-surface-candidates.js +419 -0
  17. package/dist/cjs/pm-plugins/utils/sparse-surfaces-mapping.js +108 -0
  18. package/dist/cjs/pm-plugins/utils/sparse-surfaces-state.js +53 -0
  19. package/dist/cjs/pm-plugins/utils/sparse-surfaces-view.js +134 -0
  20. package/dist/cjs/pm-plugins/utils/surface-viewport.js +223 -0
  21. package/dist/cjs/pm-plugins/utils/transactions.js +5 -0
  22. package/dist/cjs/pm-plugins/utils/validation.js +1 -1
  23. package/dist/cjs/ui/block-controls-left-surfaces.js +31 -25
  24. package/dist/cjs/ui/block-controls-right-surfaces.js +31 -25
  25. package/dist/cjs/ui/block-controls-surface-context.js +1 -0
  26. package/dist/cjs/ui/block-controls-surface-drag-handle-registration.js +6 -7
  27. package/dist/cjs/ui/block-controls-surface-drag-handle.js +6 -2
  28. package/dist/cjs/ui/consts.js +1 -1
  29. package/dist/cjs/ui/drag-handle.js +6 -4
  30. package/dist/cjs/ui/drop-target-layout.js +3 -2
  31. package/dist/cjs/ui/drop-target.js +4 -3
  32. package/dist/cjs/ui/global-styles.js +70 -28
  33. package/dist/cjs/ui/inline-drop-target.js +6 -5
  34. package/dist/cjs/ui/use-block-controls-surface-drag-source.js +1 -1
  35. package/dist/cjs/ui/utils/anchor-name.js +2 -1
  36. package/dist/cjs/ui/utils/dom-attr-name.js +3 -2
  37. package/dist/cjs/ui/utils/get-surface-placement.js +2 -1
  38. package/dist/cjs/ui/utils/partition-components-by-persistence.js +1 -1
  39. package/dist/cjs/ui/visibility-container.js +1 -1
  40. package/dist/es2019/blockControlsPlugin.js +42 -8
  41. package/dist/es2019/editor-commands/move-node.js +1 -1
  42. package/dist/es2019/editor-commands/show-drag-handle.js +14 -2
  43. package/dist/es2019/entry-points/block-decoration-utils-anchor-name.js +1 -0
  44. package/dist/es2019/entry-points/block-decoration-utils-consts.js +1 -0
  45. package/dist/es2019/entry-points/block-decoration-utils-dom-attr-name.js +1 -0
  46. package/dist/es2019/entry-points/block-decoration-utils-drag-handle-positions.js +1 -0
  47. package/dist/es2019/entry-points/block-decoration-utils-visibility-container.js +1 -0
  48. package/dist/es2019/entry-points/block-decoration-utils-widget-positions.js +1 -0
  49. package/dist/es2019/entry-points/blockControlsPlugin.js +1 -0
  50. package/dist/es2019/pm-plugins/decorations-anchor.js +3 -2
  51. package/dist/es2019/pm-plugins/decorations-drop-target-active.js +3 -2
  52. package/dist/es2019/pm-plugins/decorations-drop-target.js +3 -2
  53. package/dist/es2019/pm-plugins/decorations-surface-anchor.js +56 -0
  54. package/dist/es2019/pm-plugins/handle-mouse-down.js +2 -1
  55. package/dist/es2019/pm-plugins/handle-mouse-over.js +4 -3
  56. package/dist/es2019/pm-plugins/handle-sparse-mouse-over.js +116 -0
  57. package/dist/es2019/pm-plugins/interaction-tracking/pm-plugin.js +1 -1
  58. package/dist/es2019/pm-plugins/main.js +72 -56
  59. package/dist/es2019/pm-plugins/sparse-surfaces.js +37 -0
  60. package/dist/es2019/pm-plugins/utils/drag-handle-positions.js +1 -1
  61. package/dist/es2019/pm-plugins/utils/sparse-surface-candidates.js +305 -0
  62. package/dist/es2019/pm-plugins/utils/sparse-surfaces-mapping.js +78 -0
  63. package/dist/es2019/pm-plugins/utils/sparse-surfaces-state.js +39 -0
  64. package/dist/es2019/pm-plugins/utils/sparse-surfaces-view.js +121 -0
  65. package/dist/es2019/pm-plugins/utils/surface-viewport.js +192 -0
  66. package/dist/es2019/pm-plugins/utils/transactions.js +5 -0
  67. package/dist/es2019/pm-plugins/utils/update-selection.js +1 -2
  68. package/dist/es2019/pm-plugins/utils/validation.js +1 -1
  69. package/dist/es2019/ui/block-controls-left-surfaces.js +21 -14
  70. package/dist/es2019/ui/block-controls-right-surfaces.js +21 -14
  71. package/dist/es2019/ui/block-controls-surface-context.js +1 -0
  72. package/dist/es2019/ui/block-controls-surface-drag-handle-registration.js +4 -5
  73. package/dist/es2019/ui/block-controls-surface-drag-handle.js +6 -2
  74. package/dist/es2019/ui/consts.js +1 -1
  75. package/dist/es2019/ui/drag-handle.js +6 -4
  76. package/dist/es2019/ui/drop-target-layout.js +3 -2
  77. package/dist/es2019/ui/drop-target.js +4 -3
  78. package/dist/es2019/ui/global-styles.js +68 -29
  79. package/dist/es2019/ui/inline-drop-target.js +7 -5
  80. package/dist/es2019/ui/use-block-controls-surface-drag-source.js +1 -1
  81. package/dist/es2019/ui/utils/anchor-name.js +2 -1
  82. package/dist/es2019/ui/utils/dom-attr-name.js +3 -2
  83. package/dist/es2019/ui/utils/get-surface-placement.js +2 -1
  84. package/dist/es2019/ui/utils/partition-components-by-persistence.js +1 -1
  85. package/dist/es2019/ui/visibility-container.js +1 -1
  86. package/dist/esm/blockControlsPlugin.js +53 -17
  87. package/dist/esm/editor-commands/move-node.js +1 -1
  88. package/dist/esm/editor-commands/show-drag-handle.js +17 -5
  89. package/dist/esm/entry-points/block-decoration-utils-anchor-name.js +1 -0
  90. package/dist/esm/entry-points/block-decoration-utils-consts.js +1 -0
  91. package/dist/esm/entry-points/block-decoration-utils-dom-attr-name.js +1 -0
  92. package/dist/esm/entry-points/block-decoration-utils-drag-handle-positions.js +1 -0
  93. package/dist/esm/entry-points/block-decoration-utils-visibility-container.js +1 -0
  94. package/dist/esm/entry-points/block-decoration-utils-widget-positions.js +1 -0
  95. package/dist/esm/entry-points/blockControlsPlugin.js +1 -0
  96. package/dist/esm/pm-plugins/decorations-anchor.js +3 -2
  97. package/dist/esm/pm-plugins/decorations-drop-target-active.js +3 -2
  98. package/dist/esm/pm-plugins/decorations-drop-target.js +3 -2
  99. package/dist/esm/pm-plugins/decorations-surface-anchor.js +65 -0
  100. package/dist/esm/pm-plugins/handle-mouse-down.js +2 -1
  101. package/dist/esm/pm-plugins/handle-mouse-over.js +4 -3
  102. package/dist/esm/pm-plugins/handle-sparse-mouse-over.js +119 -0
  103. package/dist/esm/pm-plugins/interaction-tracking/pm-plugin.js +1 -1
  104. package/dist/esm/pm-plugins/main.js +68 -56
  105. package/dist/esm/pm-plugins/sparse-surfaces.js +43 -0
  106. package/dist/esm/pm-plugins/utils/drag-handle-positions.js +1 -1
  107. package/dist/esm/pm-plugins/utils/sparse-surface-candidates.js +413 -0
  108. package/dist/esm/pm-plugins/utils/sparse-surfaces-mapping.js +101 -0
  109. package/dist/esm/pm-plugins/utils/sparse-surfaces-state.js +46 -0
  110. package/dist/esm/pm-plugins/utils/sparse-surfaces-view.js +127 -0
  111. package/dist/esm/pm-plugins/utils/surface-viewport.js +217 -0
  112. package/dist/esm/pm-plugins/utils/transactions.js +5 -0
  113. package/dist/esm/pm-plugins/utils/update-selection.js +1 -2
  114. package/dist/esm/pm-plugins/utils/validation.js +1 -1
  115. package/dist/esm/ui/block-controls-left-surfaces.js +33 -27
  116. package/dist/esm/ui/block-controls-right-surfaces.js +33 -27
  117. package/dist/esm/ui/block-controls-surface-context.js +1 -0
  118. package/dist/esm/ui/block-controls-surface-drag-handle-registration.js +7 -8
  119. package/dist/esm/ui/block-controls-surface-drag-handle.js +6 -2
  120. package/dist/esm/ui/consts.js +1 -1
  121. package/dist/esm/ui/drag-handle.js +6 -4
  122. package/dist/esm/ui/drop-target-layout.js +3 -2
  123. package/dist/esm/ui/drop-target.js +4 -3
  124. package/dist/esm/ui/global-styles.js +71 -29
  125. package/dist/esm/ui/inline-drop-target.js +7 -5
  126. package/dist/esm/ui/use-block-controls-surface-drag-source.js +1 -1
  127. package/dist/esm/ui/utils/anchor-name.js +2 -1
  128. package/dist/esm/ui/utils/dom-attr-name.js +3 -2
  129. package/dist/esm/ui/utils/get-surface-placement.js +2 -1
  130. package/dist/esm/ui/utils/partition-components-by-persistence.js +1 -1
  131. package/dist/esm/ui/visibility-container.js +1 -1
  132. package/dist/types/blockControlsPluginType.d.ts +11 -4
  133. package/dist/types/pm-plugins/decorations-surface-anchor.d.ts +22 -0
  134. package/dist/types/pm-plugins/handle-sparse-mouse-over.d.ts +5 -0
  135. package/dist/types/pm-plugins/main.d.ts +2 -9
  136. package/dist/types/pm-plugins/sparse-surfaces.d.ts +8 -0
  137. package/dist/types/pm-plugins/utils/sparse-surface-candidates.d.ts +89 -0
  138. package/dist/types/pm-plugins/utils/sparse-surfaces-mapping.d.ts +20 -0
  139. package/dist/types/pm-plugins/utils/sparse-surfaces-state.d.ts +27 -0
  140. package/dist/types/pm-plugins/utils/sparse-surfaces-view.d.ts +15 -0
  141. package/dist/types/pm-plugins/utils/surface-viewport.d.ts +10 -0
  142. package/dist/types/ui/inline-drop-target.d.ts +4 -0
  143. package/dist/types/ui/utils/get-surface-placement.d.ts +3 -2
  144. package/package.json +7 -7
  145. package/dist/cjs/pm-plugins/utils/surface-node-positions.js +0 -100
  146. package/dist/es2019/pm-plugins/utils/surface-node-positions.js +0 -78
  147. package/dist/esm/pm-plugins/utils/surface-node-positions.js +0 -93
  148. package/dist/types/pm-plugins/utils/surface-node-positions.d.ts +0 -14
@@ -1,6 +1,8 @@
1
1
  import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
2
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
2
3
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
3
4
  import { findNodeDecs } from '../pm-plugins/decorations-anchor';
5
+ import { getNodeTypeWithLevel } from '../pm-plugins/decorations-common';
4
6
  import { getDecorations, key } from '../pm-plugins/main';
5
7
  import { getNestedNodePosition, getNestedNodeStartingPosition } from '../pm-plugins/utils/getNestedNodePosition';
6
8
  import { NODE_ANCHOR_ATTR_NAME, NODE_NODE_TYPE_ATTR_NAME } from '../ui/utils/dom-attr-name';
@@ -14,7 +16,6 @@ const findParentPosForHandle = state => {
14
16
  const {
15
17
  activeNode
16
18
  } = key.getState(state) || {};
17
-
18
19
  // if a node handle is already focused, return the parent pos of that node (with focused handle)
19
20
  if (activeNode && (_activeNode$handleOpt = activeNode.handleOptions) !== null && _activeNode$handleOpt !== void 0 && _activeNode$handleOpt.isFocused) {
20
21
  const $activeNodePos = state.doc.resolve(activeNode.pos);
@@ -38,7 +39,7 @@ const findParentPosForHandle = state => {
38
39
  }
39
40
 
40
41
  // else find closest parent node
41
- return expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ?
42
+ return expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration') ?
42
43
  // With native anchor enabled, all nodes have anchor name attribute despite no drag handle support, e.g. listItem, caption,
43
44
  // as opposed to old approach, node decoration is only added to the node that have drag handle,
44
45
  // hence, we need to return the exact position of the node that can have drag handle
@@ -111,6 +112,17 @@ const findNextAnchorNode = view => {
111
112
  }
112
113
  };
113
114
  export const showDragHandleAtSelection = api => (state, _, view) => {
115
+ if (api && isExperimentEnabled('platform_editor_block_control_migration')) {
116
+ const pos = findParentPosForHandle(state);
117
+ const node = pos === undefined ? undefined : state.doc.nodeAt(pos);
118
+ const anchorName = node && pos !== undefined ? api.core.actions.getAnchorIdForNode(node, pos) : undefined;
119
+ if (!node || pos === undefined || !anchorName) {
120
+ return false;
121
+ }
122
+ return api.core.actions.execute(api.blockControls.commands.showDragHandleAt(pos, anchorName, getNodeTypeWithLevel(node), {
123
+ isFocused: true
124
+ }));
125
+ }
114
126
  if (view && expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
115
127
  const anchorNode = findNextAnchorNode(view);
116
128
  if (api && anchorNode) {
@@ -1,2 +1,3 @@
1
1
  /* eslint-disable @atlaskit/editor/no-re-export */
2
+
2
3
  export { refreshAnchorName } from '../ui/utils/anchor-name';
@@ -1,2 +1,3 @@
1
1
  /* eslint-disable @atlaskit/editor/no-re-export */
2
+
2
3
  export { rootElementGap, STICKY_CONTROLS_TOP_MARGIN_FOR_STICKY_HEADER, topPositionAdjustment } from '../ui/consts';
@@ -1,2 +1,3 @@
1
1
  /* eslint-disable @atlaskit/editor/no-re-export */
2
+
2
3
  export { getAnchorAttrName } from '../ui/utils/dom-attr-name';
@@ -1,2 +1,3 @@
1
1
  /* eslint-disable @atlaskit/editor/no-re-export */
2
+
2
3
  export { getControlBottomCSSValue, getControlHeightCSSValue, getNodeHeight, getTopPosition, shouldBeSticky } from '../pm-plugins/utils/drag-handle-positions';
@@ -1,2 +1,3 @@
1
1
  /* eslint-disable @atlaskit/editor/no-re-export */
2
+
2
3
  export { VisibilityContainer } from '../ui/visibility-container';
@@ -1,2 +1,3 @@
1
1
  /* eslint-disable @atlaskit/editor/no-re-export */
2
+
2
3
  export { getRightPositionForRootElement } from '../pm-plugins/utils/widget-positions';
@@ -1,2 +1,3 @@
1
1
  /* eslint-disable @atlaskit/editor/no-re-export */
2
+
2
3
  export { blockControlsPlugin } from '../blockControlsPlugin';
@@ -1,6 +1,7 @@
1
1
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
2
- import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
2
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
3
3
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
4
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
4
5
  import { getNodeAnchor, getNodeTypeWithLevel, NESTED_DEPTH, TYPE_NODE_DEC } from './decorations-common';
5
6
  const IGNORE_NODES = ['tableCell', 'tableHeader', 'tableRow', 'listItem', 'caption', 'layoutColumn'];
6
7
  export const IGNORE_NODES_NEXT = ['tableCell', 'tableHeader', 'tableRow', 'listItem', 'caption'];
@@ -67,7 +68,7 @@ export const findNodeDecs = (state, decorations, from, to) => {
67
68
  };
68
69
  export const nodeDecorations = (newState, from, to) => {
69
70
  const decs = [];
70
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
71
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
71
72
  return [];
72
73
  }
73
74
  const docFrom = from === undefined || from < 0 ? 0 : from;
@@ -3,8 +3,9 @@ import { expandSelectionBounds } from '@atlaskit/editor-common/selection';
3
3
  import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
4
4
  import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
5
5
  import { findChildrenByType } from '@atlaskit/editor-prosemirror/utils';
6
- import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
6
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
7
7
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
8
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
8
9
  import { getNodeAnchor } from './decorations-common';
9
10
  import { createDropTargetDecoration, createLayoutDropTargetDecoration } from './decorations-drop-target';
10
11
  import { findSurroundingNodes } from './decorations-find-surrounding-nodes';
@@ -236,7 +237,7 @@ export const getActiveDropTargetDecorations = (activeDropTargetNode, state, api,
236
237
  }
237
238
  }
238
239
  }
239
- defaultActiveAnchorTracker.emit(expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? api.core.actions.getAnchorIdForNode(anchorEmitNodeWithPos.node, anchorEmitNodeWithPos.pos) || '' : getNodeAnchor(anchorEmitNodeWithPos.node));
240
+ defaultActiveAnchorTracker.emit(expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration') ? api.core.actions.getAnchorIdForNode(anchorEmitNodeWithPos.node, anchorEmitNodeWithPos.pos) || '' : getNodeAnchor(anchorEmitNodeWithPos.node));
240
241
  return {
241
242
  decsToAdd,
242
243
  decsToRemove
@@ -6,8 +6,9 @@ import { expandSelectionBounds } from '@atlaskit/editor-common/selection';
6
6
  import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
7
7
  import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
8
8
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
9
- import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
9
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
10
10
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
11
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
11
12
  import { nodeMargins } from '../ui/consts';
12
13
  import { DropTarget, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET } from '../ui/drop-target';
13
14
  import { DropTargetLayout, DropTargetLayoutNativeAnchorSupport } from '../ui/drop-target-layout';
@@ -138,7 +139,7 @@ export const createLayoutDropTargetDecoration = (pos, props, nodeViewPortalProvi
138
139
  element.setAttribute('data-blocks-drop-target-container', 'true');
139
140
  element.setAttribute('data-blocks-drop-target-key', key);
140
141
  element.style.clear = 'unset';
141
- const DropTargetLayoutComponent = expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? DropTargetLayoutNativeAnchorSupport : DropTargetLayout;
142
+ const DropTargetLayoutComponent = expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration') ? DropTargetLayoutNativeAnchorSupport : DropTargetLayout;
142
143
  nodeViewPortalProviderAPI.render(() => /*#__PURE__*/createElement(DropTargetLayoutComponent, {
143
144
  ...props,
144
145
  getPos,
@@ -0,0 +1,56 @@
1
+ import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
2
+ export const TYPE_SURFACE_ANCHOR_DEC = 'block-controls-surface-anchor';
3
+ export const SURFACE_ANCHOR_ATTR = 'data-block-controls-surface-anchor';
4
+ export const SURFACE_NODE_TYPE_ATTR = 'data-block-controls-surface-node-type';
5
+ export const SURFACE_ANCHOR_VARIABLE = '--block-controls-surface-anchor-name';
6
+
7
+ /**
8
+ * These node views expose the box used by the measured placement fallback rather than their
9
+ * ProseMirror node wrapper. The marker carries the name through a custom property so sparse CSS
10
+ * can name that inner box without adding a widget or changing the node view.
11
+ */
12
+ const INNER_CONTENT_NODE_TYPES = new Set(['blockCard', 'bodiedExtension', 'embedCard', 'extension', 'mediaSingle', 'multiBodiedExtension', 'table']);
13
+ const getMarkerStyle = (nodeType, anchorName) => {
14
+ const inheritedName = `${SURFACE_ANCHOR_VARIABLE}: ${anchorName};`;
15
+
16
+ // Inner boxes get their anchor from the sparse global selector. Naming only the node wrapper
17
+ // would position media/table/extension controls against the wrapper instead of visible content.
18
+ return INNER_CONTENT_NODE_TYPES.has(nodeType) ? inheritedName : `${inheritedName} anchor-name: ${anchorName};`;
19
+ };
20
+
21
+ /**
22
+ * Builds sparse CSS anchor decorations from already-qualified cached positions. Anchor identity is
23
+ * supplied by the editor's native node-anchor provider so sparse surfaces and consumers share the
24
+ * same `data-node-anchor`.
25
+ */
26
+ export const createSurfaceAnchorDecorations = (state, positions, resolveAnchorName, previousAnchors) => {
27
+ const anchors = new Map();
28
+ const decorations = [];
29
+ for (const position of positions) {
30
+ if (anchors.has(position)) {
31
+ continue;
32
+ }
33
+ const node = state.doc.nodeAt(position);
34
+ if (!(node !== null && node !== void 0 && node.isBlock)) {
35
+ continue;
36
+ }
37
+ const anchorName = resolveAnchorName(node, position, previousAnchors === null || previousAnchors === void 0 ? void 0 : previousAnchors.get(position));
38
+ if (!anchorName) {
39
+ continue;
40
+ }
41
+ anchors.set(position, anchorName);
42
+ decorations.push(Decoration.node(position, position + node.nodeSize, {
43
+ [SURFACE_ANCHOR_ATTR]: anchorName,
44
+ [SURFACE_NODE_TYPE_ATTR]: node.type.name,
45
+ style: getMarkerStyle(node.type.name, anchorName)
46
+ }, {
47
+ type: TYPE_SURFACE_ANCHOR_DEC,
48
+ anchorName,
49
+ nodeType: node.type.name
50
+ }));
51
+ }
52
+ return {
53
+ anchors,
54
+ decorations: DecorationSet.create(state.doc, decorations)
55
+ };
56
+ };
@@ -1,4 +1,5 @@
1
1
  import { DRAG_HANDLE_SELECTOR } from '@atlaskit/editor-common/styles';
2
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
2
3
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
3
4
  export const handleMouseDown = api => (view, event) => {
4
5
  if (!(event.target instanceof HTMLElement)) {
@@ -12,7 +13,7 @@ export const handleMouseDown = api => (view, event) => {
12
13
  if (!rootNode) {
13
14
  return false;
14
15
  }
15
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
16
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
16
17
  var _rootNode$type$name, _rootNode$type$name2;
17
18
  const anchorName = api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(rootNode, rootPos);
18
19
 
@@ -1,10 +1,11 @@
1
1
  import memoizeOne from 'memoize-one';
2
2
  import { isMultiBlockSelection } from '@atlaskit/editor-common/selection';
3
3
  import { areToolbarFlagsEnabled } from '@atlaskit/editor-common/toolbar-flag-check';
4
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
4
5
  import { fg } from '@atlaskit/platform-feature-flags/fg';
6
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
5
7
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
6
8
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
7
- import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
8
9
  import { getAnchorAttrName, getTypeNameAttrName, getTypeNameFromDom, NODE_ANCHOR_ATTR_NAME } from '../ui/utils/dom-attr-name';
9
10
  import { IGNORE_NODE_DESCENDANTS_ADVANCED_LAYOUT, IGNORE_NODES_NEXT } from './decorations-anchor';
10
11
  import { selectionPreservationPluginKey } from './selection-preservation/plugin-key';
@@ -132,7 +133,7 @@ export const handleMouseOver = (view, event, api) => {
132
133
  // Ignored via go/ees005
133
134
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
134
135
  const target = event.target;
135
- const isNativeAnchorSupported = expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true);
136
+ const isNativeAnchorSupported = expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration');
136
137
  if (target !== null && target !== void 0 && (_target$classList = target.classList) !== null && _target$classList !== void 0 && _target$classList.contains('ProseMirror')) {
137
138
  return false;
138
139
  }
@@ -204,7 +205,7 @@ export const handleMouseOver = (view, event, api) => {
204
205
  // This must happen before anchorName is read so the correct node's handle is shown.
205
206
  rootElement = redirectParagraphToWrappedMedia(rootElement, isNativeAnchorSupported);
206
207
  let anchorName;
207
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
208
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
208
209
  anchorName = rootElement.getAttribute(getAnchorAttrName());
209
210
 
210
211
  // don't show handles if we can't find an anchor
@@ -0,0 +1,116 @@
1
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
2
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
3
+ import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
4
+ import { getNodeTypeWithLevel } from './decorations-common';
5
+ const OPAQUE_BLOCKS = new Set(['table', 'bulletList', 'orderedList', 'taskList', 'decisionList', 'mediaSingle']);
6
+ const EXCLUDED_BLOCKS = new Set(['listItem', 'tableRow', 'tableCell', 'tableHeader', 'caption']);
7
+ const isPanelNodeTypeName = nodeTypeName => nodeTypeName === 'panel' || nodeTypeName === 'panel_c1' && expValEqualsNoExposure('platform_editor_controls_reliable_anchor', 'isEnabled', true) && fg('platform_editor_controls_reliable_anchor_patch_1');
8
+ const redirectParagraphToWrappedMedia = (view, $target, targetPosition) => {
9
+ const node = view.state.doc.nodeAt(targetPosition);
10
+ if (!node || node.type.name !== 'paragraph') {
11
+ return {
12
+ position: targetPosition,
13
+ node
14
+ };
15
+ }
16
+ const index = $target.index();
17
+ for (const siblingIndex of [index - 1, index + 1]) {
18
+ if (siblingIndex < 0 || siblingIndex >= $target.parent.childCount) {
19
+ continue;
20
+ }
21
+ const sibling = $target.parent.child(siblingIndex);
22
+ if ((sibling.type.name === 'mediaSingle' || sibling.type.name === 'embedCard') && (sibling.attrs.layout === 'wrap-left' || sibling.attrs.layout === 'wrap-right')) {
23
+ return {
24
+ position: siblingIndex < index ? targetPosition - sibling.nodeSize : targetPosition + node.nodeSize,
25
+ node: sibling
26
+ };
27
+ }
28
+ }
29
+ return {
30
+ position: targetPosition,
31
+ node
32
+ };
33
+ };
34
+
35
+ /** Resolves hover from PM structure so the first hover can create its sparse candidate. */
36
+ export const handleSparseMouseOver = (view, event, api) => {
37
+ var _api$editorDisabled$s, _api$editorDisabled, _api$editorDisabled$s2, _api$editorViewMode, _api$editorViewMode$s, _api$showDiff$sharedS, _api$showDiff, _api$showDiff$sharedS2, _api$userIntent, _api$userIntent$share, _$pos$nodeAfter, _controls$activeNode, _anchors$get, _anchors$get2;
38
+ const controls = api === null || api === void 0 ? void 0 : api.blockControls.sharedState.currentState();
39
+ if (!api || controls !== null && controls !== void 0 && controls.isDragging || !(event.target instanceof Element) || event.target === view.dom) {
40
+ return false;
41
+ }
42
+ const editorDisabled = (_api$editorDisabled$s = (_api$editorDisabled = api.editorDisabled) === null || _api$editorDisabled === void 0 ? void 0 : (_api$editorDisabled$s2 = _api$editorDisabled.sharedState.currentState()) === null || _api$editorDisabled$s2 === void 0 ? void 0 : _api$editorDisabled$s2.editorDisabled) !== null && _api$editorDisabled$s !== void 0 ? _api$editorDisabled$s : false;
43
+ const editorViewMode = (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : (_api$editorViewMode$s = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode$s === void 0 ? void 0 : _api$editorViewMode$s.mode;
44
+ if (editorDisabled && (editorViewMode !== 'view' || !(controls !== null && controls !== void 0 && controls.rightSideControlsEnabled))) {
45
+ return false;
46
+ }
47
+ const isDisplayingDiff = (_api$showDiff$sharedS = (_api$showDiff = api.showDiff) === null || _api$showDiff === void 0 ? void 0 : (_api$showDiff$sharedS2 = _api$showDiff.sharedState.currentState()) === null || _api$showDiff$sharedS2 === void 0 ? void 0 : _api$showDiff$sharedS2.isDisplayingChanges) !== null && _api$showDiff$sharedS !== void 0 ? _api$showDiff$sharedS : false;
48
+ const currentUserIntent = (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : (_api$userIntent$share = _api$userIntent.sharedState.currentState()) === null || _api$userIntent$share === void 0 ? void 0 : _api$userIntent$share.currentUserIntent;
49
+ if ((isDisplayingDiff || currentUserIntent === 'reviewing') && expValEqualsNoExposure('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
50
+ return false;
51
+ }
52
+ let position;
53
+ try {
54
+ position = view.posAtDOM(event.target, 0);
55
+ } catch {
56
+ return false;
57
+ }
58
+ const $pos = view.state.doc.resolve(position);
59
+ let targetPosition;
60
+ let opaque = false;
61
+ for (let depth = 1; depth <= $pos.depth; depth++) {
62
+ const node = $pos.node(depth);
63
+ if (!node.isBlock || EXCLUDED_BLOCKS.has(node.type.name)) {
64
+ continue;
65
+ }
66
+ targetPosition = $pos.before(depth);
67
+ if (OPAQUE_BLOCKS.has(node.type.name)) {
68
+ opaque = true;
69
+ break;
70
+ }
71
+ }
72
+ if (!opaque && (_$pos$nodeAfter = $pos.nodeAfter) !== null && _$pos$nodeAfter !== void 0 && _$pos$nodeAfter.isBlock && !EXCLUDED_BLOCKS.has($pos.nodeAfter.type.name)) {
73
+ // Browser positions over non-editable node chrome can resolve to the first editable child.
74
+ // Keep the ancestor unless that child actually owns the hovered DOM target.
75
+ const nodeAfterDOM = view.nodeDOM(position);
76
+ if (nodeAfterDOM instanceof Element && nodeAfterDOM.contains(event.target)) {
77
+ targetPosition = position;
78
+ }
79
+ }
80
+ if (targetPosition === undefined) {
81
+ return false;
82
+ }
83
+ const initialNode = view.state.doc.nodeAt(targetPosition);
84
+ if (!initialNode) {
85
+ return false;
86
+ }
87
+ const target = redirectParagraphToWrappedMedia(view, view.state.doc.resolve(targetPosition), targetPosition);
88
+ targetPosition = target.position;
89
+ const node = target.node;
90
+ if (!node || (controls === null || controls === void 0 ? void 0 : (_controls$activeNode = controls.activeNode) === null || _controls$activeNode === void 0 ? void 0 : _controls$activeNode.pos) === targetPosition) {
91
+ return false;
92
+ }
93
+ const $target = view.state.doc.resolve(targetPosition);
94
+ if ($target.depth > 0 && (node.type.name === 'paragraph' || node.type.name === 'heading') && node.content.size === 0) {
95
+ return false;
96
+ }
97
+ const parentNode = $target.parent;
98
+ const parentPosition = $target.depth > 0 ? $target.before($target.depth) : undefined;
99
+ const parentDOM = parentPosition === undefined ? undefined : view.nodeDOM(parentPosition);
100
+ if (isPanelNodeTypeName(parentNode.type.name) && !(parentDOM instanceof HTMLElement && parentDOM.classList.contains('ak-editor-panel__no-icon')) && $target.index() === 0) {
101
+ return false;
102
+ }
103
+ if (node.type.name === 'layoutColumn' && parentNode.type.name === 'layoutSection' && parentNode.childCount === 1 && expValEqualsNoExposure('advanced_layouts', 'isEnabled', true) && !expValEquals('platform_editor_layout_column_menu', 'isEnabled', true)) {
104
+ return false;
105
+ }
106
+ const anchors = controls === null || controls === void 0 ? void 0 : controls.surfaceAnchors;
107
+ const anchorName = (_anchors$get = anchors === null || anchors === void 0 ? void 0 : anchors.get(targetPosition)) !== null && _anchors$get !== void 0 ? _anchors$get : api.core.actions.getAnchorIdForNode(node, targetPosition);
108
+ const rootPos = $target.depth > 0 ? $target.before(1) : targetPosition;
109
+ const rootNode = view.state.doc.nodeAt(rootPos);
110
+ const rootAnchorName = (_anchors$get2 = anchors === null || anchors === void 0 ? void 0 : anchors.get(rootPos)) !== null && _anchors$get2 !== void 0 ? _anchors$get2 : rootNode ? api.core.actions.getAnchorIdForNode(rootNode, rootPos) : undefined;
111
+ if (!anchorName || !rootNode) {
112
+ return false;
113
+ }
114
+ api.core.actions.execute(api.blockControls.commands.showDragHandleAt(targetPosition, anchorName, getNodeTypeWithLevel(node), undefined, rootPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, getNodeTypeWithLevel(rootNode)));
115
+ return false;
116
+ };
@@ -1,9 +1,9 @@
1
1
  import { bind } from 'bind-event-listener';
2
2
  import { isBlockControlsSuppressionTarget } from '@atlaskit/editor-common/block-controls-suppression';
3
3
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
4
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
4
5
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
5
6
  import { UNSAFE_expValNoExposure } from '@atlaskit/platform-feature-experiments/unsafe-exp-val-no-exposure';
6
- import { PluginKey } from '@atlaskit/editor-prosemirror/state';
7
7
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
8
8
  import { RIGHT_MARGIN_ROVO_GAP_PX } from './constants';
9
9
  import { handleKeyDown } from './handle-key-down';