@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,7 +1,6 @@
1
1
  import rafSchedule from 'raf-schd';
2
2
  import { getDocument } from '@atlaskit/browser-apis';
3
3
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
4
- import { BLOCK_CONTROLS_LEFT_SURFACE, BLOCK_CONTROLS_RIGHT_SURFACE } from '@atlaskit/editor-common/block-controls/surface-keys';
5
4
  import { getBrowserInfo } from '@atlaskit/editor-common/browser';
6
5
  import { getNodeIdProvider } from '@atlaskit/editor-common/node-anchor';
7
6
  import { isMeasuring, startMeasure, stopMeasure } from '@atlaskit/editor-common/performance-measures';
@@ -12,31 +11,31 @@ import { EDIT_AREA_ID } from '@atlaskit/editor-common/ui';
12
11
  import { isEmptyDocument } from '@atlaskit/editor-common/utils';
13
12
  import { PluginKey, TextSelection } from '@atlaskit/editor-prosemirror/state';
14
13
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
15
- import { resolveSurface } from '@atlaskit/editor-ui-control-model/surface-renderer';
16
14
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
17
15
  import { fg } from '@atlaskit/platform-feature-flags/fg';
18
16
  import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element';
19
- import { combine } from '@atlaskit/pragmatic-drag-and-drop/utils/combine';
20
17
  import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element-adapter';
18
+ import { combine } from '@atlaskit/pragmatic-drag-and-drop/utils/combine';
19
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
21
20
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
22
21
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
23
- import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
24
22
  import { BLOCK_CONTROLS_SURFACE_SELECTOR } from '../ui/consts';
25
23
  import { getAnchorAttrName } from '../ui/utils/dom-attr-name';
26
24
  import { findNodeDecs, nodeDecorations } from './decorations-anchor';
25
+ import { getNodeTypeWithLevel } from './decorations-common';
27
26
  import { createActiveDragHandleNodeDecoration, dragHandleDecoration, emptyParagraphNodeDecorations, findActiveDragHandleNodeDec, findHandleDec, TYPE_ACTIVE_HANDLE_DEC } from './decorations-drag-handle';
28
27
  import { dropTargetDecorations, findDropTargetDecs } from './decorations-drop-target';
29
28
  import { getActiveDropTargetDecorations } from './decorations-drop-target-active';
30
29
  import { createActiveQuickInsertNodeDecoration, findActiveQuickInsertNodeDec, findQuickInsertInsertButtonDecoration, quickInsertButtonDecoration, TYPE_ACTIVE_QUICK_INSERT_NODE } from './decorations-quick-insert-button';
31
30
  import { handleMouseDown } from './handle-mouse-down';
32
31
  import { handleMouseOver } from './handle-mouse-over';
32
+ import { handleSparseMouseOver } from './handle-sparse-mouse-over';
33
33
  import { boundKeydownHandler } from './keymap';
34
34
  import { defaultActiveAnchorTracker } from './utils/active-anchor-tracker';
35
35
  import { getMultiSelectAnalyticsAttributes } from './utils/analytics';
36
36
  import { AnchorRectCache, isAnchorSupported } from './utils/anchor-utils';
37
37
  import { selectNode } from './utils/getSelection';
38
38
  import { getSelectedSlicePosition } from './utils/selection';
39
- import { getSurfaceNodePositions, updateSurfaceNodePositions } from './utils/surface-node-positions';
40
39
  import { getTrMetadata } from './utils/transactions';
41
40
  export const key = new PluginKey('blockControls');
42
41
  const EDITOR_BLOCKS_DRAG_INIT = 'Editor Blocks Drag Initialization Time';
@@ -233,16 +232,17 @@ const getDecorationAtPos = (state, decorations, pos, to) => {
233
232
  const nodeDecAtActivePos = nodeDecsAtActivePos.pop();
234
233
  return nodeDecAtActivePos;
235
234
  };
236
- export const apply = (api, formatMessage, tr, currentState, newState, flags, nodeViewPortalProviderAPI, nodeDecorationRegistry, rightSideControlsEnabled = false, quickInsertButtonEnabled = true, anchorRectCache, resizeObserverWidth, pragmaticCleanup, resolvedSurfaces = [], limitedModeTeardown) => {
237
- var _meta$multiSelectDnD, _api$editorViewMode, _api$editorViewMode$s, _activeNode, _activeNode2, _meta$activeNode$hand, _activeNode3, _activeNode4, _meta$isDragging2, _meta$isDragging3, _meta$toggleMenu, _meta$toggleMenu2, _meta$toggleMenu3, _meta$toggleMenu4, _meta$toggleMenu5, _meta$toggleMenu6, _meta$toggleMenu7, _meta$toggleMenu8, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging, _meta$isShiftDown, _meta$lastDragCancell;
235
+ export const apply = (api, formatMessage, tr, currentState, newState, flags, nodeViewPortalProviderAPI, nodeDecorationRegistry, rightSideControlsEnabled = false, quickInsertButtonEnabled = true, anchorRectCache, resizeObserverWidth, pragmaticCleanup, limitedModeTeardown) => {
236
+ var _meta$multiSelectDnD, _api$editorViewMode, _api$editorViewMode$s, _activeNode, _activeNode2, _meta$activeNode$hand, _activeNode3, _activeNode4, _meta$isDragging2, _meta$toggleMenu, _meta$isDragging3, _meta$toggleMenu2, _meta$toggleMenu3, _meta$toggleMenu4, _meta$toggleMenu5, _meta$toggleMenu6, _meta$toggleMenu7, _meta$toggleMenu8, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging, _meta$isShiftDown, _meta$lastDragCancell;
238
237
  let {
239
238
  activeNode,
240
239
  decorations,
241
240
  isResizerResizing,
242
- multiSelectDnD,
241
+ multiSelectDnD
242
+ } = currentState;
243
+ const {
243
244
  surfaceNodePositions
244
245
  } = currentState;
245
- const previousActiveNode = activeNode;
246
246
  const {
247
247
  editorHeight,
248
248
  editorWidthLeft,
@@ -391,13 +391,28 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
391
391
  if (activeNode.rootPos !== undefined) {
392
392
  mappedRootPos = tr.mapping.mapResult(activeNode.rootPos, -1);
393
393
  }
394
+ let mappedNodeType = activeNode.nodeType;
395
+ let mappedRootNodeType = activeNode.rootNodeType;
396
+ // Sparse mode does not redraw the old decorations. A block-type transaction may report
397
+ // a text range that excludes the active block position, so always refresh the already
398
+ // active node and root from the new document (for example, paragraph → heading-1).
399
+ if (isExperimentEnabled('platform_editor_block_control_migration')) {
400
+ const mappedNode = newState.doc.nodeAt(mappedPos.pos);
401
+ if (mappedNode !== null && mappedNode !== void 0 && mappedNode.isBlock) {
402
+ mappedNodeType = getNodeTypeWithLevel(mappedNode);
403
+ }
404
+ const mappedRootNode = mappedRootPos ? mappedRootPos.pos === mappedPos.pos && mappedNode ? mappedNode : newState.doc.nodeAt(mappedRootPos.pos) : undefined;
405
+ if (mappedRootNode !== null && mappedRootNode !== void 0 && mappedRootNode.isBlock) {
406
+ mappedRootNodeType = getNodeTypeWithLevel(mappedRootNode);
407
+ }
408
+ }
394
409
  activeNode = {
395
410
  pos: mappedPos.pos,
396
411
  anchorName: activeNode.anchorName,
397
- nodeType: activeNode.nodeType,
412
+ nodeType: mappedNodeType,
398
413
  rootPos: (_mappedRootPos$pos = (_mappedRootPos = mappedRootPos) === null || _mappedRootPos === void 0 ? void 0 : _mappedRootPos.pos) !== null && _mappedRootPos$pos !== void 0 ? _mappedRootPos$pos : activeNode.rootPos,
399
414
  rootAnchorName: activeNode.rootAnchorName,
400
- rootNodeType: activeNode.rootNodeType
415
+ rootNodeType: mappedRootNodeType
401
416
  };
402
417
  }
403
418
  }
@@ -433,7 +448,7 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
433
448
  const isNodeDecsMissing = isDecSetEmpty || maybeNodeCountChanged || editorExperiment('platform_editor_breakout_resizing', true) && hasJustFinishedResizing;
434
449
  const shouldRedrawNodeDecs = !isResizerResizing && (isNodeDecsMissing || (meta === null || meta === void 0 ? void 0 : meta.isDragging)) &&
435
450
  // Skip expensive anchor node decoration recalculations when native anchor support is enabled
436
- !expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true);
451
+ !(expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration'));
437
452
  let isActiveNodeModified = false;
438
453
  if (api && shouldRedrawNodeDecs) {
439
454
  const oldNodeDecs = findNodeDecs(newState, decorations, from, to);
@@ -507,14 +522,14 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
507
522
  // In view mode with right-side controls, remove any lingering drag handle decorations
508
523
  // (they may carry over from edit mode). Only remove drag handles specifically, not
509
524
  // the remix button decorations (those are managed separately via showInViewMode).
510
- if (flags.legacyDragHandleEnabled && isViewMode && rightSideControlsEnabled) {
525
+ if (!isExperimentEnabled('platform_editor_block_control_migration') && isViewMode && rightSideControlsEnabled) {
511
526
  const allHandleDecs = findHandleDec(decorations, 0, newState.doc.content.size);
512
527
  if (allHandleDecs.length > 0) {
513
528
  decorations = decorations.remove(allHandleDecs);
514
529
  }
515
530
  }
516
531
  if (shouldRemoveHandle) {
517
- if (flags.legacyDragHandleEnabled) {
532
+ if (!isExperimentEnabled('platform_editor_block_control_migration')) {
518
533
  var _activeNode5, _activeNode6;
519
534
  const oldHandle = findHandleDec(decorations, (_activeNode5 = activeNode) === null || _activeNode5 === void 0 ? void 0 : _activeNode5.pos, (_activeNode6 = activeNode) === null || _activeNode6 === void 0 ? void 0 : _activeNode6.pos);
520
535
  decorations = decorations.remove(oldHandle);
@@ -526,7 +541,7 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
526
541
  // after a doc change (e.g. pressing Enter splits a node), DecorationSet.map() can shift the
527
542
  // decoration to a different position, so a point-range search would miss it and leave a stale
528
543
  // attribute on the wrong DOM node.
529
- if ((flags.legacyDragHandleEnabled || nodeDecorationRegistry.length > 0) && expValEquals('platform_editor_controls_reliable_anchor', 'isEnabled', true)) {
544
+ if ((!isExperimentEnabled('platform_editor_block_control_migration') || nodeDecorationRegistry.length > 0) && expValEquals('platform_editor_controls_reliable_anchor', 'isEnabled', true)) {
530
545
  const oldActiveNodeDec = findActiveDragHandleNodeDec(decorations, 0, newState.doc.content.size);
531
546
  decorations = decorations.remove(oldActiveNodeDec);
532
547
  const oldActiveQuickInsertDec = findActiveQuickInsertNodeDec(decorations, 0, newState.doc.content.size);
@@ -560,7 +575,7 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
560
575
  } else if (api) {
561
576
  var _latestActiveNode5, _latestActiveNode10;
562
577
  // The registry surface replaces the legacy drag-handle decorations during migration.
563
- if (flags.legacyDragHandleEnabled && shouldRecreateHandle && (!rightSideControlsEnabled || !isViewMode)) {
578
+ if (!isExperimentEnabled('platform_editor_block_control_migration') && shouldRecreateHandle && (!rightSideControlsEnabled || !isViewMode)) {
564
579
  var _activeNode11, _activeNode12, _latestActiveNode, _latestActiveNode2, _latestActiveNode3, _latestActiveNode4;
565
580
  const oldHandle = findHandleDec(decorations, (_activeNode11 = activeNode) === null || _activeNode11 === void 0 ? void 0 : _activeNode11.pos, (_activeNode12 = activeNode) === null || _activeNode12 === void 0 ? void 0 : _activeNode12.pos);
566
581
  decorations = decorations.remove(oldHandle);
@@ -577,7 +592,7 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
577
592
  });
578
593
  decorations = decorations.add(newState.doc, [handleDec]);
579
594
  }
580
- if ((flags.legacyDragHandleEnabled ||
595
+ if ((!isExperimentEnabled('platform_editor_block_control_migration') ||
581
596
  // nodeDecorationRegistry consumers (e.g. the legacy Remix button) rely
582
597
  // on that same anchor-name for their own CSS anchor() positioning, so this must still run
583
598
  // when such a consumer exists even if the legacy drag handle itself is disabled.
@@ -788,7 +803,10 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
788
803
  }
789
804
  }
790
805
  const isEmptyDoc = isEmptyDocument(newState.doc);
791
- if (isEmptyDoc && !expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
806
+ if (isExperimentEnabled('platform_editor_block_control_migration') && (meta === null || meta === void 0 ? void 0 : meta.isDragging) === false) {
807
+ decorations = decorations.remove(findNodeDecs(newState, decorations));
808
+ }
809
+ if (isEmptyDoc && !(expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration'))) {
792
810
  const hasNodeDecoration = !!findNodeDecs(newState, decorations).length;
793
811
  if (!hasNodeDecoration) {
794
812
  decorations = decorations.add(newState.doc, [emptyParagraphNodeDecorations()]);
@@ -801,27 +819,31 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
801
819
  // remove isEmptyDoc check and let decorations render and determine their own visibility
802
820
  // In view mode with right-side controls we render node decorations (right-edge button), not the
803
821
  // handle - so findHandleDec is always empty. Don't clear activeNode in that case.
804
- const hasHandleOrViewModeControls = !flags.legacyDragHandleEnabled || isViewMode && rightSideControlsEnabled || findHandleDec(decorations, (_latestActiveNode11 = latestActiveNode) === null || _latestActiveNode11 === void 0 ? void 0 : _latestActiveNode11.pos, (_latestActiveNode12 = latestActiveNode) === null || _latestActiveNode12 === void 0 ? void 0 : _latestActiveNode12.pos).length > 0;
822
+ const hasHandleOrViewModeControls = isExperimentEnabled('platform_editor_block_control_migration') || isViewMode && rightSideControlsEnabled || findHandleDec(decorations, (_latestActiveNode11 = latestActiveNode) === null || _latestActiveNode11 === void 0 ? void 0 : _latestActiveNode11.pos, (_latestActiveNode12 = latestActiveNode) === null || _latestActiveNode12 === void 0 ? void 0 : _latestActiveNode12.pos).length > 0;
805
823
  // Keep the registry surface mounted while its Block Menu owns focus.
806
- const keepActiveNodeForOpenBlockMenu = !flags.legacyDragHandleEnabled && isMenuOpen;
824
+ const keepActiveNodeForOpenBlockMenu = isExperimentEnabled('platform_editor_block_control_migration') && isMenuOpen;
807
825
  newActiveNode = meta !== null && meta !== void 0 && meta.editorBlurred && !keepActiveNodeForOpenBlockMenu || !(meta !== null && meta !== void 0 && meta.activeNode) && !hasHandleOrViewModeControls ? null : latestActiveNode;
808
826
  } else {
809
827
  var _latestActiveNode13, _latestActiveNode14;
810
- newActiveNode = isEmptyDoc || !(meta !== null && meta !== void 0 && meta.activeNode) && flags.legacyDragHandleEnabled && findHandleDec(decorations, (_latestActiveNode13 = latestActiveNode) === null || _latestActiveNode13 === void 0 ? void 0 : _latestActiveNode13.pos, (_latestActiveNode14 = latestActiveNode) === null || _latestActiveNode14 === void 0 ? void 0 : _latestActiveNode14.pos).length === 0 ? null : latestActiveNode;
811
- }
812
- if (flags.surfaceNodePositionsEnabled && resolvedSurfaces.length > 0) {
813
- surfaceNodePositions = updateSurfaceNodePositions({
814
- activeNode: newActiveNode,
815
- currentPositions: surfaceNodePositions,
816
- from,
817
- newState,
818
- previousActiveNode,
819
- resolvedSurfaces,
820
- to,
821
- tr
822
- });
828
+ newActiveNode = isEmptyDoc || !(meta !== null && meta !== void 0 && meta.activeNode) && !isExperimentEnabled('platform_editor_block_control_migration') && findHandleDec(decorations, (_latestActiveNode13 = latestActiveNode) === null || _latestActiveNode13 === void 0 ? void 0 : _latestActiveNode13.pos, (_latestActiveNode14 = latestActiveNode) === null || _latestActiveNode14 === void 0 ? void 0 : _latestActiveNode14.pos).length === 0 ? null : latestActiveNode;
823
829
  }
824
830
  let isMenuOpenNew = isMenuOpen;
831
+ let nextMenuTriggerByNode = (meta === null || meta === void 0 ? void 0 : (_meta$toggleMenu = meta.toggleMenu) === null || _meta$toggleMenu === void 0 ? void 0 : _meta$toggleMenu.triggerByNode) || menuTriggerByNode;
832
+ if (isExperimentEnabled('platform_editor_block_control_migration') && tr.docChanged && menuTriggerByNode && !(meta !== null && meta !== void 0 && meta.toggleMenu)) {
833
+ var _menuTriggerByNode$ro, _newState$doc$nodeAt4;
834
+ const mapped = tr.mapping.mapResult(menuTriggerByNode.pos, 1);
835
+ const mappedRoot = tr.mapping.mapResult((_menuTriggerByNode$ro = menuTriggerByNode.rootPos) !== null && _menuTriggerByNode$ro !== void 0 ? _menuTriggerByNode$ro : menuTriggerByNode.pos, 1);
836
+ if (mapped.deleted || mappedRoot.deleted || !((_newState$doc$nodeAt4 = newState.doc.nodeAt(mapped.pos)) !== null && _newState$doc$nodeAt4 !== void 0 && _newState$doc$nodeAt4.isBlock)) {
837
+ nextMenuTriggerByNode = undefined;
838
+ isMenuOpenNew = false;
839
+ } else {
840
+ nextMenuTriggerByNode = {
841
+ ...menuTriggerByNode,
842
+ pos: mapped.pos,
843
+ rootPos: mappedRoot.pos
844
+ };
845
+ }
846
+ }
825
847
  if (meta !== null && meta !== void 0 && meta.closeMenu) {
826
848
  isMenuOpenNew = false;
827
849
  } else if (meta !== null && meta !== void 0 && meta.toggleMenu) {
@@ -841,8 +863,8 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
841
863
  activeDropTargetNode: currentActiveDropTargetNode,
842
864
  isDragging: (_meta$isDragging3 = meta === null || meta === void 0 ? void 0 : meta.isDragging) !== null && _meta$isDragging3 !== void 0 ? _meta$isDragging3 : isDragging,
843
865
  isMenuOpen: isMenuOpenNew,
844
- menuTriggerBy: (meta === null || meta === void 0 ? void 0 : (_meta$toggleMenu = meta.toggleMenu) === null || _meta$toggleMenu === void 0 ? void 0 : _meta$toggleMenu.anchorName) || menuTriggerBy,
845
- menuTriggerByNode: (meta === null || meta === void 0 ? void 0 : (_meta$toggleMenu2 = meta.toggleMenu) === null || _meta$toggleMenu2 === void 0 ? void 0 : _meta$toggleMenu2.triggerByNode) || menuTriggerByNode,
866
+ menuTriggerBy: (meta === null || meta === void 0 ? void 0 : (_meta$toggleMenu2 = meta.toggleMenu) === null || _meta$toggleMenu2 === void 0 ? void 0 : _meta$toggleMenu2.anchorName) || menuTriggerBy,
867
+ menuTriggerByNode: nextMenuTriggerByNode,
846
868
  blockMenuOptions: {
847
869
  canMoveUp: (meta === null || meta === void 0 ? void 0 : (_meta$toggleMenu3 = meta.toggleMenu) === null || _meta$toggleMenu3 === void 0 ? void 0 : _meta$toggleMenu3.moveUp) !== undefined ? meta === null || meta === void 0 ? void 0 : (_meta$toggleMenu4 = meta.toggleMenu) === null || _meta$toggleMenu4 === void 0 ? void 0 : _meta$toggleMenu4.moveUp : blockMenuOptions === null || blockMenuOptions === void 0 ? void 0 : blockMenuOptions.canMoveUp,
848
870
  canMoveDown: (meta === null || meta === void 0 ? void 0 : (_meta$toggleMenu5 = meta.toggleMenu) === null || _meta$toggleMenu5 === void 0 ? void 0 : _meta$toggleMenu5.moveDown) !== undefined ? meta === null || meta === void 0 ? void 0 : (_meta$toggleMenu6 = meta.toggleMenu) === null || _meta$toggleMenu6 === void 0 ? void 0 : _meta$toggleMenu6.moveDown : blockMenuOptions === null || blockMenuOptions === void 0 ? void 0 : blockMenuOptions.canMoveDown,
@@ -860,8 +882,7 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
860
882
  isSelectedViaDragHandle: isSelectedViaDragHandleNew
861
883
  };
862
884
  };
863
- export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecorationRegistry, rightSideControlsEnabled = false, quickInsertButtonEnabled = true, legacyDragHandleEnabled = true) => {
864
- var _api$uiControlRegistr, _api$uiControlRegistr2, _api$uiControlRegistr3, _api$uiControlRegistr4;
885
+ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecorationRegistry, rightSideControlsEnabled = false, quickInsertButtonEnabled = true) => {
865
886
  const {
866
887
  formatMessage
867
888
  } = getIntl();
@@ -869,15 +890,9 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
869
890
  exposure: true
870
891
  });
871
892
  const toolbarFlagsEnabled = areToolbarFlagsEnabled(Boolean(api === null || api === void 0 ? void 0 : api.toolbar));
872
- // Mirrors `registryBlockControlsEnabled` in blockControlsPlugin.tsx: `legacyDragHandleEnabled` is
873
- // only false once that gate is on.
874
- const surfaceNodePositionsEnabled = !legacyDragHandleEnabled;
875
893
  const flags = {
876
- legacyDragHandleEnabled,
877
- surfaceNodePositionsEnabled,
878
894
  toolbarFlagsEnabled
879
895
  };
880
- const resolvedSurfaces = surfaceNodePositionsEnabled ? [resolveSurface((_api$uiControlRegistr = api === null || api === void 0 ? void 0 : (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(BLOCK_CONTROLS_LEFT_SURFACE)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [], BLOCK_CONTROLS_LEFT_SURFACE), resolveSurface((_api$uiControlRegistr3 = api === null || api === void 0 ? void 0 : (_api$uiControlRegistr4 = api.uiControlRegistry) === null || _api$uiControlRegistr4 === void 0 ? void 0 : _api$uiControlRegistr4.actions.getComponents(BLOCK_CONTROLS_RIGHT_SURFACE)) !== null && _api$uiControlRegistr3 !== void 0 ? _api$uiControlRegistr3 : [], BLOCK_CONTROLS_RIGHT_SURFACE)] : [];
881
896
  let anchorRectCache;
882
897
  if (!isAnchorSupported()) {
883
898
  anchorRectCache = new AnchorRectCache();
@@ -891,13 +906,10 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
891
906
  return new SafePlugin({
892
907
  key,
893
908
  state: {
894
- init(_config, editorState) {
895
- return {
896
- ...initialState,
897
- surfaceNodePositions: resolvedSurfaces.length > 0 ? getSurfaceNodePositions(editorState, resolvedSurfaces) : []
898
- };
899
- },
900
- apply: (tr, currentState, _, newState) => apply(api, formatMessage, tr, currentState, newState, flags, nodeViewPortalProviderAPI, nodeDecorationRegistry, rightSideControlsEnabled, quickInsertButtonEnabled, anchorRectCache, resizeObserverWidth, pragmaticCleanup, resolvedSurfaces, limitedModeTeardown)
909
+ init: () => ({
910
+ ...initialState
911
+ }),
912
+ apply: (tr, currentState, _, newState) => apply(api, formatMessage, tr, currentState, newState, flags, nodeViewPortalProviderAPI, nodeDecorationRegistry, rightSideControlsEnabled, quickInsertButtonEnabled, anchorRectCache, resizeObserverWidth, pragmaticCleanup, limitedModeTeardown)
901
913
  },
902
914
  props: {
903
915
  decorations: state => {
@@ -917,7 +929,7 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
917
929
  let decorationSet = (_key$getState2 = key.getState(state)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.decorations;
918
930
  // In view mode with right-side controls, remove any lingering drag-handle decorations
919
931
  // (created in edit mode) that may not have been cleaned up on mode switch.
920
- if (decorationSet && legacyDragHandleEnabled && rightSideControlsEnabled && (api === null || api === void 0 ? void 0 : (_api$editorViewMode3 = api.editorViewMode) === null || _api$editorViewMode3 === void 0 ? void 0 : (_api$editorViewMode3$ = _api$editorViewMode3.sharedState.currentState()) === null || _api$editorViewMode3$ === void 0 ? void 0 : _api$editorViewMode3$.mode) === 'view') {
932
+ if (decorationSet && !isExperimentEnabled('platform_editor_block_control_migration') && rightSideControlsEnabled && (api === null || api === void 0 ? void 0 : (_api$editorViewMode3 = api.editorViewMode) === null || _api$editorViewMode3 === void 0 ? void 0 : (_api$editorViewMode3$ = _api$editorViewMode3.sharedState.currentState()) === null || _api$editorViewMode3$ === void 0 ? void 0 : _api$editorViewMode3$.mode) === 'view') {
921
933
  const handleDecs = findHandleDec(decorationSet, 0, state.doc.content.size);
922
934
  if (handleDecs.length > 0) {
923
935
  decorationSet = decorationSet.remove(handleDecs);
@@ -1070,10 +1082,14 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
1070
1082
  // another layer of protection to prevent handling mouseover
1071
1083
  // when native anchor with dnd is enabled in limited mode
1072
1084
  // in case there are descripancies between getNodeIdProvider limited mode state
1073
- if ((_getNodeIdProvider = getNodeIdProvider(view)) !== null && _getNodeIdProvider !== void 0 && _getNodeIdProvider.isLimitedMode() && expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
1085
+ if ((_getNodeIdProvider = getNodeIdProvider(view)) !== null && _getNodeIdProvider !== void 0 && _getNodeIdProvider.isLimitedMode() && (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration'))) {
1074
1086
  return;
1075
1087
  }
1076
- handleMouseOver(view, event, api);
1088
+ if (isExperimentEnabled('platform_editor_block_control_migration')) {
1089
+ handleSparseMouseOver(view, event, api);
1090
+ } else {
1091
+ handleMouseOver(view, event, api);
1092
+ }
1077
1093
  return false;
1078
1094
  },
1079
1095
  mousedown: (view, event) => {
@@ -1136,7 +1152,7 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
1136
1152
  if (editorExperiment('platform_editor_controls', 'variant1')) {
1137
1153
  var _api$core2;
1138
1154
  // Focus moving into the registry surface remains inside the editor experience.
1139
- const isChildOfSurface = !flags.legacyDragHandleEnabled && event.relatedTarget instanceof HTMLElement && event.relatedTarget.closest(BLOCK_CONTROLS_SURFACE_SELECTOR) !== null;
1155
+ const isChildOfSurface = isExperimentEnabled('platform_editor_block_control_migration') && event.relatedTarget instanceof HTMLElement && event.relatedTarget.closest(BLOCK_CONTROLS_SURFACE_SELECTOR) !== null;
1140
1156
  const shouldPreserveRemixInlineDropdownFocus = event.relatedTarget instanceof HTMLElement && event.relatedTarget.closest('[data-editor-remix-inline-dropdown-preserve-focus]') !== null;
1141
1157
  const isChildOfEditor = event.relatedTarget instanceof HTMLElement && event.relatedTarget.closest(`#${EDIT_AREA_ID}`) !== null;
1142
1158
 
@@ -1178,7 +1194,7 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
1178
1194
 
1179
1195
  // Registry surfaces have their own ResizeObservers and absolute placement.
1180
1196
  // Width metadata only drives legacy widget recreation.
1181
- if (legacyDragHandleEnabled && !isResizerResizing) {
1197
+ if (!isExperimentEnabled('platform_editor_block_control_migration') && !isResizerResizing) {
1182
1198
  const editorContentArea = entries[0].target;
1183
1199
  // Ignored via go/ees005
1184
1200
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -1198,7 +1214,7 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
1198
1214
  }
1199
1215
  }
1200
1216
  }));
1201
- const shouldObserve = expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? !isAnchorSupported() : true;
1217
+ const shouldObserve = !(expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) || !isAnchorSupported();
1202
1218
  if (editorContentArea && shouldObserve) {
1203
1219
  resizeObserverWidth.observe(editorContentArea);
1204
1220
  }
@@ -0,0 +1,37 @@
1
+ import { BLOCK_CONTROLS_SURFACE_INVALIDATION } from '@atlaskit/editor-common/block-controls/surface-candidate-invalidation';
2
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
4
+ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
5
+ import { key as blockControlsKey } from './main';
6
+ import { emptySparseSurfaceCandidateState } from './utils/sparse-surface-candidates';
7
+ import { applySparseSurfacesTransaction, createInitialSparseSurfacesState } from './utils/sparse-surfaces-state';
8
+ import { createSparseSurfacesView } from './utils/sparse-surfaces-view';
9
+ export const sparseSurfacesKey = new PluginKey('blockControlsSparseSurfaces');
10
+
11
+ /** Owns sparse anchors independently of drag/drop decorations and their lifecycle. */
12
+ export const createSparseSurfacesPlugin = api => new SafePlugin({
13
+ key: sparseSurfacesKey,
14
+ state: {
15
+ init: () => createInitialSparseSurfacesState(emptySparseSurfaceCandidateState),
16
+ apply(tr, previous, _oldState, newState) {
17
+ return applySparseSurfacesTransaction({
18
+ invalidation: tr.getMeta(BLOCK_CONTROLS_SURFACE_INVALIDATION),
19
+ meta: tr.getMeta(sparseSurfacesKey),
20
+ newState,
21
+ previous,
22
+ tr
23
+ });
24
+ }
25
+ },
26
+ props: {
27
+ decorations(state) {
28
+ var _api$limitedMode, _api$limitedMode$shar, _blockControlsKey$get, _sparseSurfacesKey$ge;
29
+ return api !== null && api !== void 0 && (_api$limitedMode = api.limitedMode) !== null && _api$limitedMode !== void 0 && (_api$limitedMode$shar = _api$limitedMode.sharedState.currentState()) !== null && _api$limitedMode$shar !== void 0 && _api$limitedMode$shar.enabled || (_blockControlsKey$get = blockControlsKey.getState(state)) !== null && _blockControlsKey$get !== void 0 && _blockControlsKey$get.isDragging ? DecorationSet.empty : (_sparseSurfacesKey$ge = sparseSurfacesKey.getState(state)) === null || _sparseSurfacesKey$ge === void 0 ? void 0 : _sparseSurfacesKey$ge.decorations;
30
+ }
31
+ },
32
+ view: view => createSparseSurfacesView({
33
+ api,
34
+ pluginKey: sparseSurfacesKey,
35
+ view
36
+ })
37
+ });
@@ -1,7 +1,7 @@
1
1
  import memoizeOne from 'memoize-one';
2
2
  import { DRAG_HANDLE_WIDTH } from '@atlaskit/editor-common/styles';
3
- import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
4
3
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
4
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
5
5
  import { DRAG_HANDLE_DIVIDER_TOP_ADJUSTMENT, DRAG_HANDLE_H1_TOP_ADJUSTMENT, DRAG_HANDLE_H2_TOP_ADJUSTMENT, DRAG_HANDLE_H4_TOP_ADJUSTMENT, DRAG_HANDLE_H5_TOP_ADJUSTMENT, DRAG_HANDLE_H6_TOP_ADJUSTMENT, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_PARAGRAPH_SMALL_TOP_ADJUSTMENT, DRAG_HANDLE_PARAGRAPH_TOP_ADJUSTMENT, dragHandleGap } from '../../ui/consts';
6
6
  const STICKY_NODES = ['panel', 'table', 'expand', 'layoutSection', 'bodiedExtension'];
7
7
  export const getTopPosition = (dom, type) => {