@atlaskit/editor-plugin-block-controls 20.0.3 → 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 (107) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cjs/blockControlsPlugin.js +53 -17
  3. package/dist/cjs/editor-commands/show-drag-handle.js +17 -5
  4. package/dist/cjs/pm-plugins/decorations-anchor.js +2 -1
  5. package/dist/cjs/pm-plugins/decorations-drop-target-active.js +2 -1
  6. package/dist/cjs/pm-plugins/decorations-drop-target.js +2 -1
  7. package/dist/cjs/pm-plugins/decorations-surface-anchor.js +72 -0
  8. package/dist/cjs/pm-plugins/handle-mouse-down.js +2 -1
  9. package/dist/cjs/pm-plugins/handle-mouse-over.js +3 -2
  10. package/dist/cjs/pm-plugins/handle-sparse-mouse-over.js +125 -0
  11. package/dist/cjs/pm-plugins/main.js +66 -54
  12. package/dist/cjs/pm-plugins/sparse-surfaces.js +49 -0
  13. package/dist/cjs/pm-plugins/utils/sparse-surface-candidates.js +419 -0
  14. package/dist/cjs/pm-plugins/utils/sparse-surfaces-mapping.js +108 -0
  15. package/dist/cjs/pm-plugins/utils/sparse-surfaces-state.js +53 -0
  16. package/dist/cjs/pm-plugins/utils/sparse-surfaces-view.js +134 -0
  17. package/dist/cjs/pm-plugins/utils/surface-viewport.js +223 -0
  18. package/dist/cjs/pm-plugins/utils/transactions.js +5 -0
  19. package/dist/cjs/ui/block-controls-left-surfaces.js +31 -25
  20. package/dist/cjs/ui/block-controls-right-surfaces.js +31 -25
  21. package/dist/cjs/ui/block-controls-surface-context.js +1 -0
  22. package/dist/cjs/ui/block-controls-surface-drag-handle-registration.js +6 -7
  23. package/dist/cjs/ui/block-controls-surface-drag-handle.js +6 -2
  24. package/dist/cjs/ui/drag-handle.js +5 -3
  25. package/dist/cjs/ui/drop-target-layout.js +3 -2
  26. package/dist/cjs/ui/drop-target.js +3 -2
  27. package/dist/cjs/ui/global-styles.js +69 -27
  28. package/dist/cjs/ui/inline-drop-target.js +6 -5
  29. package/dist/cjs/ui/utils/anchor-name.js +2 -1
  30. package/dist/cjs/ui/utils/dom-attr-name.js +3 -2
  31. package/dist/cjs/ui/utils/get-surface-placement.js +2 -1
  32. package/dist/es2019/blockControlsPlugin.js +42 -8
  33. package/dist/es2019/editor-commands/show-drag-handle.js +14 -2
  34. package/dist/es2019/pm-plugins/decorations-anchor.js +2 -1
  35. package/dist/es2019/pm-plugins/decorations-drop-target-active.js +2 -1
  36. package/dist/es2019/pm-plugins/decorations-drop-target.js +2 -1
  37. package/dist/es2019/pm-plugins/decorations-surface-anchor.js +56 -0
  38. package/dist/es2019/pm-plugins/handle-mouse-down.js +2 -1
  39. package/dist/es2019/pm-plugins/handle-mouse-over.js +3 -2
  40. package/dist/es2019/pm-plugins/handle-sparse-mouse-over.js +116 -0
  41. package/dist/es2019/pm-plugins/main.js +70 -54
  42. package/dist/es2019/pm-plugins/sparse-surfaces.js +37 -0
  43. package/dist/es2019/pm-plugins/utils/sparse-surface-candidates.js +305 -0
  44. package/dist/es2019/pm-plugins/utils/sparse-surfaces-mapping.js +78 -0
  45. package/dist/es2019/pm-plugins/utils/sparse-surfaces-state.js +39 -0
  46. package/dist/es2019/pm-plugins/utils/sparse-surfaces-view.js +121 -0
  47. package/dist/es2019/pm-plugins/utils/surface-viewport.js +192 -0
  48. package/dist/es2019/pm-plugins/utils/transactions.js +5 -0
  49. package/dist/es2019/ui/block-controls-left-surfaces.js +21 -14
  50. package/dist/es2019/ui/block-controls-right-surfaces.js +21 -14
  51. package/dist/es2019/ui/block-controls-surface-context.js +1 -0
  52. package/dist/es2019/ui/block-controls-surface-drag-handle-registration.js +4 -5
  53. package/dist/es2019/ui/block-controls-surface-drag-handle.js +6 -2
  54. package/dist/es2019/ui/drag-handle.js +5 -3
  55. package/dist/es2019/ui/drop-target-layout.js +3 -2
  56. package/dist/es2019/ui/drop-target.js +3 -2
  57. package/dist/es2019/ui/global-styles.js +67 -28
  58. package/dist/es2019/ui/inline-drop-target.js +6 -5
  59. package/dist/es2019/ui/utils/anchor-name.js +2 -1
  60. package/dist/es2019/ui/utils/dom-attr-name.js +3 -2
  61. package/dist/es2019/ui/utils/get-surface-placement.js +2 -1
  62. package/dist/esm/blockControlsPlugin.js +53 -17
  63. package/dist/esm/editor-commands/show-drag-handle.js +17 -5
  64. package/dist/esm/pm-plugins/decorations-anchor.js +2 -1
  65. package/dist/esm/pm-plugins/decorations-drop-target-active.js +2 -1
  66. package/dist/esm/pm-plugins/decorations-drop-target.js +2 -1
  67. package/dist/esm/pm-plugins/decorations-surface-anchor.js +65 -0
  68. package/dist/esm/pm-plugins/handle-mouse-down.js +2 -1
  69. package/dist/esm/pm-plugins/handle-mouse-over.js +3 -2
  70. package/dist/esm/pm-plugins/handle-sparse-mouse-over.js +119 -0
  71. package/dist/esm/pm-plugins/main.js +66 -54
  72. package/dist/esm/pm-plugins/sparse-surfaces.js +43 -0
  73. package/dist/esm/pm-plugins/utils/sparse-surface-candidates.js +413 -0
  74. package/dist/esm/pm-plugins/utils/sparse-surfaces-mapping.js +101 -0
  75. package/dist/esm/pm-plugins/utils/sparse-surfaces-state.js +46 -0
  76. package/dist/esm/pm-plugins/utils/sparse-surfaces-view.js +127 -0
  77. package/dist/esm/pm-plugins/utils/surface-viewport.js +217 -0
  78. package/dist/esm/pm-plugins/utils/transactions.js +5 -0
  79. package/dist/esm/ui/block-controls-left-surfaces.js +33 -27
  80. package/dist/esm/ui/block-controls-right-surfaces.js +33 -27
  81. package/dist/esm/ui/block-controls-surface-context.js +1 -0
  82. package/dist/esm/ui/block-controls-surface-drag-handle-registration.js +7 -8
  83. package/dist/esm/ui/block-controls-surface-drag-handle.js +6 -2
  84. package/dist/esm/ui/drag-handle.js +5 -3
  85. package/dist/esm/ui/drop-target-layout.js +3 -2
  86. package/dist/esm/ui/drop-target.js +3 -2
  87. package/dist/esm/ui/global-styles.js +70 -28
  88. package/dist/esm/ui/inline-drop-target.js +6 -5
  89. package/dist/esm/ui/utils/anchor-name.js +2 -1
  90. package/dist/esm/ui/utils/dom-attr-name.js +3 -2
  91. package/dist/esm/ui/utils/get-surface-placement.js +2 -1
  92. package/dist/types/blockControlsPluginType.d.ts +10 -3
  93. package/dist/types/pm-plugins/decorations-surface-anchor.d.ts +22 -0
  94. package/dist/types/pm-plugins/handle-sparse-mouse-over.d.ts +5 -0
  95. package/dist/types/pm-plugins/main.d.ts +2 -9
  96. package/dist/types/pm-plugins/sparse-surfaces.d.ts +8 -0
  97. package/dist/types/pm-plugins/utils/sparse-surface-candidates.d.ts +89 -0
  98. package/dist/types/pm-plugins/utils/sparse-surfaces-mapping.d.ts +20 -0
  99. package/dist/types/pm-plugins/utils/sparse-surfaces-state.d.ts +27 -0
  100. package/dist/types/pm-plugins/utils/sparse-surfaces-view.d.ts +15 -0
  101. package/dist/types/pm-plugins/utils/surface-viewport.d.ts +10 -0
  102. package/dist/types/ui/utils/get-surface-placement.d.ts +3 -2
  103. package/package.json +5 -5
  104. package/dist/cjs/pm-plugins/utils/surface-node-positions.js +0 -100
  105. package/dist/es2019/pm-plugins/utils/surface-node-positions.js +0 -78
  106. package/dist/esm/pm-plugins/utils/surface-node-positions.js +0 -93
  107. package/dist/types/pm-plugins/utils/surface-node-positions.d.ts +0 -14
@@ -3,11 +3,11 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
3
3
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
4
  import React from 'react';
5
5
  import { BLOCK_CONTROL_UI_CONTEXT } from '@atlaskit/editor-common/block-controls/block-control-ui-context';
6
- import { BLOCK_CONTROLS_LEFT_GROUP } from '@atlaskit/editor-common/block-controls/surface-keys';
6
+ import { BLOCK_CONTROLS_DRAG_HANDLE, BLOCK_CONTROLS_LEFT_GROUP } from '@atlaskit/editor-common/block-controls/surface-keys';
7
7
  import { BlockControlsSurfaceDragHandle } from './block-controls-surface-drag-handle';
8
8
  export var getBlockControlsSurfaceDragHandleComponents = function getBlockControlsSurfaceDragHandleComponents(_ref) {
9
9
  var api = _ref.api;
10
- return [{
10
+ return [_objectSpread(_objectSpread({
11
11
  component: function component(_ref2) {
12
12
  var surfaceContext = _ref2.surfaceContext;
13
13
  return /*#__PURE__*/React.createElement(BlockControlsSurfaceDragHandle, {
@@ -19,12 +19,11 @@ export var getBlockControlsSurfaceDragHandleComponents = function getBlockContro
19
19
  var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
20
20
  surfaceContext = _ref3.surfaceContext;
21
21
  var context = surfaceContext === null || surfaceContext === void 0 ? void 0 : surfaceContext.get(BLOCK_CONTROL_UI_CONTEXT);
22
- return !(context !== null && context !== void 0 && context.activeNode) || context.targetNode.pos !== context.activeNode.pos;
23
- },
24
- key: 'block-controls-drag-handle',
22
+ return !(context !== null && context !== void 0 && context.activeNode) || context.targetNode.pos !== context.activeNode.pos || context.activeControlKey !== undefined && context.activeControlKey !== BLOCK_CONTROLS_DRAG_HANDLE.key;
23
+ }
24
+ }, BLOCK_CONTROLS_DRAG_HANDLE), {}, {
25
25
  parents: [_objectSpread(_objectSpread({}, BLOCK_CONTROLS_LEFT_GROUP), {}, {
26
26
  rank: 200
27
- })],
28
- type: 'button'
29
- }];
27
+ })]
28
+ })];
30
29
  };
@@ -118,7 +118,11 @@ export var BlockControlsSurfaceDragHandle = function BlockControlsSurfaceDragHan
118
118
  return !isTopLevelNode || $anchor.depth > DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH;
119
119
  }, [api, isLayoutColumn, isShiftDown, isTopLevelNode, view]);
120
120
  var getAnchorName = useCallback(function () {
121
- var _ref2, _ref3, _dom$getAttribute, _dom$closest;
121
+ var _api$blockControls$sh2, _ref2, _ref3, _dom$getAttribute, _dom$closest;
122
+ var surfaceAnchor = posRef.current === undefined ? undefined : api === null || api === void 0 || (_api$blockControls$sh2 = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh2 === void 0 || (_api$blockControls$sh2 = _api$blockControls$sh2.surfaceAnchors) === null || _api$blockControls$sh2 === void 0 ? void 0 : _api$blockControls$sh2.get(posRef.current);
123
+ if (surfaceAnchor) {
124
+ return surfaceAnchor;
125
+ }
122
126
  if (activeNodeAnchorName) {
123
127
  return activeNodeAnchorName;
124
128
  }
@@ -132,7 +136,7 @@ export var BlockControlsSurfaceDragHandle = function BlockControlsSurfaceDragHan
132
136
  }
133
137
  var anchorAttrName = getAnchorAttrName();
134
138
  return (_ref2 = (_ref3 = (_dom$getAttribute = dom.getAttribute(anchorAttrName)) !== null && _dom$getAttribute !== void 0 ? _dom$getAttribute : dom.getAttribute(NODE_ANCHOR_ATTR_NAME)) !== null && _ref3 !== void 0 ? _ref3 : (_dom$closest = dom.closest("[".concat(anchorAttrName, "]"))) === null || _dom$closest === void 0 ? void 0 : _dom$closest.getAttribute(anchorAttrName)) !== null && _ref2 !== void 0 ? _ref2 : '';
135
- }, [activeNodeAnchorName, view]);
139
+ }, [activeNodeAnchorName, api, view]);
136
140
  useLayoutEffect(function () {
137
141
  var element = buttonRef.current;
138
142
  if (!view || !element) {
@@ -736,10 +736,12 @@ export var DragHandle = function DragHandle(_ref2) {
736
736
  });
737
737
  }, [anchorName, api, getPos, nodeType, start, view]);
738
738
  var calculatePositionOld = useCallback(function () {
739
+ var _$pos$nodeAfter;
739
740
  var pos = getPos();
740
- var $pos = expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? typeof pos === 'number' && view.state.doc.resolve(pos) : pos && view.state.doc.resolve(pos);
741
+ var $pos = typeof pos === 'number' ? view.state.doc.resolve(pos) : undefined;
741
742
  var parentPos = $pos && $pos.depth ? $pos.before() : undefined;
742
743
  var node = parentPos !== undefined ? view.state.doc.nodeAt(parentPos) : undefined;
744
+ var nodeTypeWithLevel = $pos !== null && $pos !== void 0 && (_$pos$nodeAfter = $pos.nodeAfter) !== null && _$pos$nodeAfter !== void 0 && _$pos$nodeAfter.isBlock ? getNodeTypeWithLevel($pos.nodeAfter) : nodeType;
743
745
  var parentNodeType = node === null || node === void 0 ? void 0 : node.type.name;
744
746
  var supportsAnchor = CSS.supports('top', "anchor(".concat(anchorName, " start)")) && CSS.supports('left', "anchor(".concat(anchorName, " start)"));
745
747
  var safeAnchorName = editorExperiment('platform_editor_controls', 'variant1') ? refreshAnchorName({
@@ -797,13 +799,13 @@ export var DragHandle = function DragHandle(_ref2) {
797
799
  var bottom = editorExperiment('platform_editor_controls', 'variant1') ? getControlBottomCSSValue(safeAnchorName, isSticky, isTopLevelNodeValue, isLayoutColumn, ACTIVE_DRAG_HANDLE_FALLBACK_ANCHOR_NAME) : {};
798
800
  return _objectSpread({
799
801
  left: isEdgeCase ? "calc(".concat(anchorStart, " + ").concat(getLeftPosition(dom, nodeType, innerContainer, isMacroInteractionUpdates, parentNodeType), ")") : editorExperiment('advanced_layouts', true) && isLayoutColumn ? "calc((".concat(anchorRight, " + ").concat(anchorLeft, ")/2 - ").concat(DRAG_HANDLE_HEIGHT / 2, "px)") : "calc(".concat(anchorStart, " - ").concat(DRAG_HANDLE_WIDTH, "px - ").concat(dragHandleGap(nodeType, parentNodeType), "px)"),
800
- top: editorExperiment('advanced_layouts', true) && isLayoutColumn ? "calc(".concat(anchorTop, " - ").concat(DRAG_HANDLE_WIDTH, "px)") : "calc(".concat(anchorStart, " + ").concat(topPositionAdjustment(expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? $pos && $pos.nodeAfter && getNodeTypeWithLevel($pos.nodeAfter) || nodeType : nodeType, (dom === null || dom === void 0 ? void 0 : dom.getAttribute('layout')) || ''), "px)")
802
+ top: editorExperiment('advanced_layouts', true) && isLayoutColumn ? "calc(".concat(anchorTop, " - ").concat(DRAG_HANDLE_WIDTH, "px)") : "calc(".concat(anchorStart, " + ").concat(topPositionAdjustment(nodeTypeWithLevel, (dom === null || dom === void 0 ? void 0 : dom.getAttribute('layout')) || ''), "px)")
801
803
  }, bottom);
802
804
  }
803
805
  var height = editorExperiment('platform_editor_controls', 'variant1') ? getControlHeightCSSValue(getNodeHeight(dom, safeAnchorName, anchorRectCache) || 0, isSticky, isTopLevelNodeValue, "".concat(DRAG_HANDLE_HEIGHT), isLayoutColumn) : {};
804
806
  return _objectSpread({
805
807
  left: isEdgeCase ? "calc(".concat((dom === null || dom === void 0 ? void 0 : dom.offsetLeft) || 0, "px + ").concat(getLeftPosition(dom, nodeType, innerContainer, isMacroInteractionUpdates, parentNodeType), ")") : getLeftPosition(dom, nodeType, innerContainer, isMacroInteractionUpdates, parentNodeType),
806
- top: getTopPosition(dom, nodeType)
808
+ top: getTopPosition(dom, nodeTypeWithLevel)
807
809
  }, height);
808
810
  }, [anchorName, getPos, view, nodeType, blockCardWidth, macroInteractionUpdates, anchorRectCache, isTopLevelNodeValue, isLayoutColumn]);
809
811
  var isReliableAnchorEnabled = expValEquals('platform_editor_controls_reliable_anchor', 'isEnabled', true);
@@ -9,6 +9,7 @@ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } fr
9
9
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports
10
10
  import { css, jsx } from '@emotion/react';
11
11
  import { layoutBreakpointWidth } from '@atlaskit/editor-shared-styles';
12
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
12
13
  import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box';
13
14
  import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element-adapter';
14
15
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
@@ -121,7 +122,7 @@ export var DropTargetLayout = function DropTargetLayout(props) {
121
122
  }, isDraggedOver ? jsx(DropIndicator, {
122
123
  edge: "right",
123
124
  gap: "-".concat(DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH, "px")
124
- }) : (isActiveAnchor || expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) && jsx("div", {
125
+ }) : (isActiveAnchor || expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) && jsx("div", {
125
126
  "data-testid": "block-ctrl-drop-hint",
126
127
  css: dropTargetLayoutHintStyle
127
128
  }));
@@ -236,7 +237,7 @@ export var DropTargetLayoutNativeAnchorSupport = function DropTargetLayoutNative
236
237
  }, isDraggedOver ? jsx(DropIndicator, {
237
238
  edge: "right",
238
239
  gap: "-".concat(DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH, "px")
239
- }) : (isActiveAnchor || expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) && jsx("div", {
240
+ }) : (isActiveAnchor || expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) && jsx("div", {
240
241
  "data-testid": "block-ctrl-drop-hint",
241
242
  css: dropTargetLayoutHintStyle
242
243
  }));
@@ -10,6 +10,7 @@ import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
10
10
  import { css, jsx } from '@emotion/react';
11
11
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
12
12
  import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
13
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
13
14
  import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box';
14
15
  import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element-adapter';
15
16
  import { layers } from '@atlaskit/theme/constants';
@@ -86,7 +87,7 @@ var HoverZone = function HoverZone(_ref) {
86
87
  var ref = useRef(null);
87
88
  var isRemainingheight = dropTargetStyle === 'remainingHeight';
88
89
  var anchorName = useMemo(function () {
89
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
90
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
90
91
  if (node && typeof pos === 'number') {
91
92
  var posOffset = position === 'upper' ? -node.nodeSize : 0;
92
93
  return (api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(node, pos + posOffset)) || '';
@@ -140,7 +141,7 @@ var HoverZone = function HoverZone(_ref) {
140
141
  // only apply upper drop zone
141
142
  if (isRemainingheight && position === 'upper') {
142
143
  // previous node
143
- var _anchorName = node ? expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? (api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(node, pos || -1)) || '' : getNodeAnchor(node) : '';
144
+ var _anchorName = node ? expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration') ? (api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(node, pos || -1)) || '' : getNodeAnchor(node) : '';
144
145
  var top = 'unset';
145
146
  if (_anchorName) {
146
147
  var enabledDropZone = getEnableDropZone().includes((node === null || node === void 0 ? void 0 : node.type.name) || '');
@@ -13,7 +13,7 @@ import { akEditorBreakoutPadding, akEditorCalculatedWideLayoutWidth, akEditorCal
13
13
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
14
14
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
15
15
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
16
- import { ACTIVE_DRAG_HANDLE_ATTR, ACTIVE_DRAG_HANDLE_FALLBACK_ANCHOR_NAME, ACTIVE_QUICK_INSERT_ATTR, ACTIVE_QUICK_INSERT_FALLBACK_ANCHOR_NAME, DRAG_HANDLE_MAX_WIDTH_PLUS_GAP } from './consts';
16
+ import { ACTIVE_DRAG_HANDLE_FALLBACK_ANCHOR_NAME, ACTIVE_QUICK_INSERT_FALLBACK_ANCHOR_NAME, DRAG_HANDLE_MAX_WIDTH_PLUS_GAP } from './consts';
17
17
  import { NODE_ANCHOR_ATTR_NAME } from './utils/dom-attr-name';
18
18
 
19
19
  /**
@@ -369,17 +369,70 @@ var staticControlsAnchorStyles = css({
369
369
  }
370
370
  }
371
371
  });
372
+ var sparseSurfaceAnchorName = 'var(--block-controls-surface-anchor-name)';
372
373
 
373
- /**
374
- * Names the CSS anchor on top-level nodes, so the block controls surfaces can anchor to the blocks
375
- * they render against. Only top-level at the moment as we don't have use cases yet for persistent controls that are nested.
376
- */
377
- var surfaceAnchorStyles = css({
374
+ // Inner node-view boxes own the visible geometry for these nodes. The root arm keeps a sparse
375
+ // marker useful when a node view has not mounted its inner box yet.
376
+ var sparseSurfaceAnchorStyles = css({
378
377
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors
379
- '.ProseMirror': _defineProperty({}, "[".concat(NODE_ANCHOR_ATTR_NAME, "]:not([").concat(NODE_ANCHOR_ATTR_NAME, "] [").concat(NODE_ANCHOR_ATTR_NAME, "]):not([").concat(ACTIVE_DRAG_HANDLE_ATTR, "], [").concat(ACTIVE_QUICK_INSERT_ATTR, "])"), {
380
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/ui-styling-standard/no-imported-style-values
381
- anchorName: "var(".concat(ANCHOR_VARIABLE_NAME, ", attr(data-node-anchor type(<custom-ident>)))")
382
- })
378
+ '.ProseMirror': {
379
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
380
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="blockCard"]:has(.datasourceView-content-inner-wrap) .datasourceView-content-inner-wrap': {
381
+ anchorName: sparseSurfaceAnchorName
382
+ },
383
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
384
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="blockCard"]:not(:has(.datasourceView-content-inner-wrap))': {
385
+ anchorName: sparseSurfaceAnchorName
386
+ },
387
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
388
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="bodiedExtension"]:has(.extension-container[data-layout]) .extension-container[data-layout]': {
389
+ anchorName: sparseSurfaceAnchorName
390
+ },
391
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
392
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="bodiedExtension"]:not(:has(.extension-container[data-layout]))': {
393
+ anchorName: sparseSurfaceAnchorName
394
+ },
395
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
396
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="embedCard"]:has(.rich-media-item) .rich-media-item': {
397
+ anchorName: sparseSurfaceAnchorName
398
+ },
399
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
400
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="embedCard"]:not(:has(.rich-media-item))': {
401
+ anchorName: sparseSurfaceAnchorName
402
+ },
403
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
404
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="extension"]:has(.extension-container[data-layout]) .extension-container[data-layout]': {
405
+ anchorName: sparseSurfaceAnchorName
406
+ },
407
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
408
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="extension"]:not(:has(.extension-container[data-layout]))': {
409
+ anchorName: sparseSurfaceAnchorName
410
+ },
411
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
412
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="mediaSingle"]:has(.resizer-item) .resizer-item': {
413
+ anchorName: sparseSurfaceAnchorName
414
+ },
415
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
416
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="mediaSingle"]:not(:has(.resizer-item))': {
417
+ anchorName: sparseSurfaceAnchorName
418
+ },
419
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
420
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="multiBodiedExtension"]:has(.extension-container[data-layout]) .extension-container[data-layout]': {
421
+ anchorName: sparseSurfaceAnchorName
422
+ },
423
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
424
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="multiBodiedExtension"]:not(:has(.extension-container[data-layout]))': {
425
+ anchorName: sparseSurfaceAnchorName
426
+ },
427
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
428
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="table"]:has(.resizer-item) .resizer-item': {
429
+ anchorName: sparseSurfaceAnchorName
430
+ },
431
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
432
+ '[data-block-controls-surface-anchor][data-block-controls-surface-node-type="table"]:not(:has(.resizer-item))': {
433
+ anchorName: sparseSurfaceAnchorName
434
+ }
435
+ }
383
436
  });
384
437
 
385
438
  // Styles applied to nodes with anchors when dragging
@@ -419,33 +472,22 @@ export var GlobalStylesWrapper = function GlobalStylesWrapper(_ref) {
419
472
  };
420
473
  }),
421
474
  isDraggingFromState = _useSharedPluginState.isDragging;
422
- var isDragging = expValEquals('platform_editor_block_controls_perf_optimization', 'isEnabled', true) ? isDraggingFromState : false;
475
+ var sparseSurfacesEnabled = isExperimentEnabled('platform_editor_block_control_migration');
476
+ var isDragging = sparseSurfacesEnabled || expValEquals('platform_editor_block_controls_perf_optimization', 'isEnabled', true) ? isDraggingFromState : false;
423
477
  var shouldRenderAnchors = isCSSAnchorSupported() && expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true);
424
-
425
- // The surfaces anchor to blocks they render against rather than only to the hovered one, so they
426
- // need a name on every node. Added alongside whichever conditional rule applies rather than
427
- // replacing it: this one matches only non-active nodes, so the two sets are disjoint.
428
- //
429
- // The migration check is what scopes this. Unlike the surfaces, this component renders for every
430
- // editor, so without it the rule would name anchors on documents that have no surface to anchor.
431
- var shouldRenderSurfaceAnchors =
432
- // eslint-disable-next-line @atlaskit/platform/no-preconditioning -- browser capability, not a flag: an anchor name is meaningless where `anchor()` cannot resolve
433
- Boolean(isCSSAnchorSupported()) && isExperimentEnabled('platform_editor_block_control_migration');
478
+ var sparseSurfaceAnchorsEnabled = Boolean(isCSSAnchorSupported()) && sparseSurfacesEnabled;
434
479
  var toolbarFlagsEnabled = areToolbarFlagsEnabled(Boolean(api === null || api === void 0 ? void 0 : api.toolbar));
435
480
  return jsx(Global
436
481
  // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
437
482
  , {
438
- styles: [globalStyles(), globalDnDStyle, expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? extendedHoverZoneNext() : extendedHoverZone(), isDragging && (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? extendedDragZoneNext : extendedDragZone), editorExperiment('platform_editor_preview_panel_responsiveness', true, {
483
+ styles: [globalStyles(), globalDnDStyle, (!sparseSurfacesEnabled || isDragging) && (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration') ? extendedHoverZoneNext() : extendedHoverZone()), isDragging && (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration') ? extendedDragZoneNext : extendedDragZone), (!sparseSurfacesEnabled || isDragging) && editorExperiment('platform_editor_preview_panel_responsiveness', true, {
439
484
  exposure: true
440
- }) ? expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? extendHoverZoneReducedNext : extendHoverZoneReduced : undefined,
485
+ }) ? expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration') ? extendHoverZoneReducedNext : extendHoverZoneReduced : undefined,
441
486
  // platform_editor_controls note: this allows drag handles to render on empty lines
442
- toolbarFlagsEnabled ? undefined : withInlineNodeStyle, withDeleteLinesStyleFix, withMediaSingleStyleFix, legacyBreakoutWideLayoutStyle, headingWithIndentationInLayoutStyleFix, editorExperiment('advanced_layouts', true) ? blockCardWithoutLayout : undefined, withDividerInPanelStyleFix, withFormatInLayoutStyleFix, expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? withRelativePosStyleNext : withRelativePosStyle, expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? withAnchorNameZindexStyleNext : withAnchorNameZindexStyle, expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) && expValEquals('advanced_layouts', 'isEnabled', true) ? layoutColumnExtendedHoverZone : layoutColumnWithoutHoverZone, expValEquals('platform_editor_controls_reliable_anchor', 'isEnabled', true) ?
487
+ toolbarFlagsEnabled ? undefined : withInlineNodeStyle, withDeleteLinesStyleFix, withMediaSingleStyleFix, legacyBreakoutWideLayoutStyle, headingWithIndentationInLayoutStyleFix, editorExperiment('advanced_layouts', true) ? blockCardWithoutLayout : undefined, withDividerInPanelStyleFix, withFormatInLayoutStyleFix, (!sparseSurfacesEnabled || isDragging) && (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration') ? withRelativePosStyleNext : withRelativePosStyle), (!sparseSurfacesEnabled || isDragging) && (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration') ? withAnchorNameZindexStyleNext : withAnchorNameZindexStyle), (!sparseSurfacesEnabled || isDragging) && ((expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) && expValEquals('advanced_layouts', 'isEnabled', true) ? layoutColumnExtendedHoverZone : layoutColumnWithoutHoverZone), sparseSurfaceAnchorsEnabled ? isDragging ? dragAnchorStyles : false : expValEquals('platform_editor_controls_reliable_anchor', 'isEnabled', true) ?
443
488
  // dragAnchorStyles sets anchor-name on ALL nodes during drag (needed for drop target positioning).
444
489
  // staticControlsAnchorStyles handles anchor-name via node decorations for non-drag state.
445
490
  // shouldRenderAnchors guards both: only apply anchor styles on browsers that support CSS anchor positioning.
446
- shouldRenderAnchors ? isDragging ? dragAnchorStyles : staticControlsAnchorStyles : false : shouldRenderAnchors && (isDragging ? dragAnchorStyles : dragHandlerAnchorStyles),
447
- // Last so that, at equal specificity, the surfaces' own anchor names are the ones that
448
- // stand. It cannot overlap the active-node rules above, which this selector excludes.
449
- shouldRenderSurfaceAnchors && surfaceAnchorStyles]
491
+ shouldRenderAnchors ? isDragging ? dragAnchorStyles : staticControlsAnchorStyles : false : shouldRenderAnchors && (isDragging ? dragAnchorStyles : dragHandlerAnchorStyles), sparseSurfaceAnchorsEnabled && sparseSurfaceAnchorStyles]
450
492
  });
451
493
  };
@@ -11,6 +11,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
11
11
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports
12
12
  import { css, jsx } from '@emotion/react';
13
13
  import { akEditorBreakoutPadding } from '@atlaskit/editor-shared-styles';
14
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
14
15
  import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box';
15
16
  import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element-adapter';
16
17
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
@@ -92,7 +93,7 @@ export var InlineDropTarget = function InlineDropTarget(_ref) {
92
93
  isDraggedOver = _useState2[0],
93
94
  setIsDraggedOver = _useState2[1];
94
95
  var anchorName = useMemo(function () {
95
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
96
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
96
97
  var _getPos;
97
98
  return nextNode ? (api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(nextNode, (_getPos = getPos()) !== null && _getPos !== void 0 ? _getPos : -1)) || '' : '';
98
99
  }
@@ -125,7 +126,7 @@ export var InlineDropTarget = function InlineDropTarget(_ref) {
125
126
  innerContainerWidth = "calc(var(--ak-editor--line-length) * ".concat(percentageWidth, ")");
126
127
  }
127
128
  } else if (nextNode.type.name === 'table' && nextNode.firstChild) {
128
- var tableWidthAnchor = expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? typeof nextNodePos === 'number' ? (api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(nextNode.firstChild, nextNodePos + 1)) || '' : '' : getNodeAnchor(nextNode.firstChild);
129
+ var tableWidthAnchor = expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration') ? typeof nextNodePos === 'number' ? (api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(nextNode.firstChild, nextNodePos + 1)) || '' : '' : getNodeAnchor(nextNode.firstChild);
129
130
  var isNumberColumnEnabled = Boolean(nextNode.attrs.isNumberColumnEnabled);
130
131
  if (isAnchorSupported()) {
131
132
  innerContainerWidth = isNumberColumnEnabled ? "calc(anchor-size(".concat(tableWidthAnchor, " width) + ").concat(TABLE_NUMBERED_COLUMN_WIDTH, "px)") : "anchor-size(".concat(tableWidthAnchor, " width)");
@@ -138,7 +139,7 @@ export var InlineDropTarget = function InlineDropTarget(_ref) {
138
139
  innerContainerWidth = "min(".concat(nextNode.attrs.width, "px, ").concat(innerContainerWidth, ")");
139
140
  }
140
141
  } else if (nextNode.type.name === 'mediaSingle' && nextNode.firstChild) {
141
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
142
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
142
143
  var _nextNode$firstChild;
143
144
  // check pos is a number
144
145
  if (typeof nextNodePos === 'number' && ((_nextNode$firstChild = nextNode.firstChild) === null || _nextNode$firstChild === void 0 ? void 0 : _nextNode$firstChild.type.name) === 'media') {
@@ -153,7 +154,7 @@ export var InlineDropTarget = function InlineDropTarget(_ref) {
153
154
  var heightTargetAnchorName = targetAnchorName;
154
155
  if (nextNode.type.name === 'layoutSection' && nextNode.firstChild && nextNode.lastChild) {
155
156
  if (isLeftPosition) {
156
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
157
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
157
158
  if (typeof nextNodePos === 'number') {
158
159
  heightTargetAnchorName = (api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(nextNode.firstChild, nextNodePos + 1)) || '';
159
160
  } else {
@@ -163,7 +164,7 @@ export var InlineDropTarget = function InlineDropTarget(_ref) {
163
164
  heightTargetAnchorName = getNodeAnchor(nextNode.firstChild);
164
165
  }
165
166
  } else {
166
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
167
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
167
168
  if (typeof nextNodePos === 'number') {
168
169
  var lastNodeStartPos = nextNode.content.size - nextNode.lastChild.nodeSize;
169
170
  heightTargetAnchorName = (api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(nextNode.lastChild, lastNodeStartPos + 1)) || '';
@@ -1,3 +1,4 @@
1
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
1
2
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
2
3
  import { findNodeDecs } from '../../pm-plugins/decorations-anchor';
3
4
  import { key } from '../../pm-plugins/main';
@@ -10,7 +11,7 @@ export var refreshAnchorName = function refreshAnchorName(_ref) {
10
11
  view = _ref.view,
11
12
  anchorName = _ref.anchorName;
12
13
  var newAnchorName = anchorName || '';
13
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
14
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
14
15
  return newAnchorName;
15
16
  }
16
17
  var pos = getPos();
@@ -1,14 +1,15 @@
1
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
1
2
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
2
3
  export var NODE_ANCHOR_ATTR_NAME = 'data-node-anchor';
3
4
  export var NODE_NODE_TYPE_ATTR_NAME = 'data-prosemirror-node-name';
4
5
  export var getAnchorAttrName = function getAnchorAttrName() {
5
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
6
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
6
7
  return NODE_ANCHOR_ATTR_NAME;
7
8
  }
8
9
  return 'data-drag-handler-anchor-name';
9
10
  };
10
11
  export var getTypeNameAttrName = function getTypeNameAttrName() {
11
- if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
12
+ if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) || isExperimentEnabled('platform_editor_block_control_migration')) {
12
13
  return NODE_NODE_TYPE_ATTR_NAME;
13
14
  }
14
15
  return 'data-drag-handler-node-type';
@@ -98,6 +98,7 @@ var INVALID_ANCHOR_FALLBACK_TOP = "-".concat(INVALID_ANCHOR_OFFSCREEN_PX, "px");
98
98
  var INVALID_ANCHOR_FALLBACK_BOTTOM = "".concat(INVALID_ANCHOR_OFFSCREEN_PX, "px");
99
99
  export var getAnchoredSurfacePlacement = function getAnchoredSurfacePlacement(_ref3) {
100
100
  var anchorName = _ref3.anchorName,
101
+ layout = _ref3.layout,
101
102
  nodeType = _ref3.nodeType,
102
103
  nodeTypeWithLevel = _ref3.nodeTypeWithLevel,
103
104
  parentNodeType = _ref3.parentNodeType,
@@ -124,7 +125,7 @@ export var getAnchoredSurfacePlacement = function getAnchoredSurfacePlacement(_r
124
125
  } : {}), {}, {
125
126
  left: side === 'right' ? "calc(anchor(".concat(anchorName, " right) + ").concat(gap, "px)") : "anchor(".concat(anchorName, " left)"),
126
127
  positionAnchor: anchorName,
127
- top: "calc(anchor(".concat(anchorName, " top, ").concat(INVALID_ANCHOR_FALLBACK_TOP, ") + ").concat(topPositionAdjustment(nodeTypeWithLevel), "px)"),
128
+ top: "calc(anchor(".concat(anchorName, " top, ").concat(INVALID_ANCHOR_FALLBACK_TOP, ") + ").concat(topPositionAdjustment(nodeTypeWithLevel, layout), "px)"),
128
129
  // The left side grows away from the node without knowing its own width, so it pulls itself
129
130
  // back past its own box and the gap. The right side grows into the margin, so the gap is
130
131
  // already folded into `left` above.
@@ -13,7 +13,7 @@ import type { LimitedModePlugin } from '@atlaskit/editor-plugin-limited-mode';
13
13
  import type { MetricsPlugin } from '@atlaskit/editor-plugin-metrics';
14
14
  import type { QuickInsertPlugin } from '@atlaskit/editor-plugin-quick-insert';
15
15
  import type { SelectionPlugin } from '@atlaskit/editor-plugin-selection';
16
- import type { ShowDiffPlugin } from '@atlaskit/editor-plugin-show-diff';
16
+ import type { ShowDiffPlugin } from '@atlaskit/editor-plugin-show-diff/show-diff-plugin-type';
17
17
  import type { ToolbarPlugin } from '@atlaskit/editor-plugin-toolbar';
18
18
  import type { TypeAheadPlugin } from '@atlaskit/editor-plugin-type-ahead';
19
19
  import type { UiControlRegistryPlugin } from '@atlaskit/editor-plugin-ui-control-registry/ui-control-registry-plugin-type';
@@ -24,6 +24,7 @@ import type { Mapping } from '@atlaskit/editor-prosemirror/transform';
24
24
  import type { Decoration, DecorationSet, EditorView } from '@atlaskit/editor-prosemirror/view';
25
25
  export type ActiveNode = {
26
26
  anchorName: string;
27
+ controlKey?: string;
27
28
  handleOptions?: HandleOptions;
28
29
  nodeType: string;
29
30
  pos: number;
@@ -115,11 +116,14 @@ export type BlockControlsSharedState = {
115
116
  preservedSelection?: Selection;
116
117
  /** Whether left/right hover split is enabled (from plugin config) */
117
118
  rightSideControlsEnabled?: boolean;
118
- surfaceNodePositions?: number[];
119
+ surfaceActiveNodes?: ReadonlyMap<number, ActiveNode>;
120
+ surfaceAnchors?: ReadonlyMap<number, string>;
121
+ surfaceNodePositions?: readonly number[];
119
122
  } | undefined;
120
- export type HandleOptions = {
123
+ export type ControlOptions = {
121
124
  isFocused: boolean;
122
125
  } | undefined;
126
+ export type HandleOptions = ControlOptions;
123
127
  /**
124
128
  * Props passed to custom right-edge button components (e.g. config.rightEdgeButton).
125
129
  */
@@ -225,6 +229,9 @@ export type BlockControlsPlugin = NextEditorPlugin<'blockControls', {
225
229
  setMultiSelectPositions: (anchor?: number, head?: number) => EditorCommand;
226
230
  setNodeDragged: (getPos: () => number | undefined, anchorName: string, nodeType: string) => EditorCommand;
227
231
  setSelectedViaDragHandle: (isSelectedViaDragHandle?: boolean) => EditorCommand;
232
+ showControlAtPosition: (pos: number, control: {
233
+ key: string;
234
+ }, options?: ControlOptions) => EditorCommand;
228
235
  showDragHandleAt: (pos: number, anchorName: string, nodeType: string, handleOptions?: HandleOptions, rootPos?: number, rootAnchorName?: string, rootNodeType?: string) => EditorCommand;
229
236
  /**
230
237
  * Starts preserving the current selection across transactions.
@@ -0,0 +1,22 @@
1
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
+ import type { EditorState } from '@atlaskit/editor-prosemirror/state';
3
+ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
4
+ export declare const TYPE_SURFACE_ANCHOR_DEC = "block-controls-surface-anchor";
5
+ export declare const SURFACE_ANCHOR_ATTR = "data-block-controls-surface-anchor";
6
+ export declare const SURFACE_NODE_TYPE_ATTR = "data-block-controls-surface-node-type";
7
+ export declare const SURFACE_ANCHOR_VARIABLE = "--block-controls-surface-anchor-name";
8
+ export type SurfaceAnchorDecorationSpec = {
9
+ anchorName: string;
10
+ nodeType: string;
11
+ type: typeof TYPE_SURFACE_ANCHOR_DEC;
12
+ };
13
+ export type SurfaceAnchorDecorationResult = {
14
+ anchors: ReadonlyMap<number, string>;
15
+ decorations: DecorationSet;
16
+ };
17
+ /**
18
+ * Builds sparse CSS anchor decorations from already-qualified cached positions. Anchor identity is
19
+ * supplied by the editor's native node-anchor provider so sparse surfaces and consumers share the
20
+ * same `data-node-anchor`.
21
+ */
22
+ export declare const createSurfaceAnchorDecorations: (state: EditorState, positions: readonly number[], resolveAnchorName: (node: PMNode, position: number, previousAnchorName: string | undefined) => string | undefined, previousAnchors?: ReadonlyMap<number, string>) => SurfaceAnchorDecorationResult;
@@ -0,0 +1,5 @@
1
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
+ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
3
+ import type { BlockControlsPlugin } from '../blockControlsPluginType';
4
+ /** Resolves hover from PM structure so the first hover can create its sparse candidate. */
5
+ export declare const handleSparseMouseOver: (view: EditorView, event: Event, api: ExtractInjectionAPI<BlockControlsPlugin> | undefined) => boolean;
@@ -5,21 +5,14 @@ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
5
5
  import type { EditorState, ReadonlyTransaction, Transaction } from '@atlaskit/editor-prosemirror/state';
6
6
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
7
7
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
8
- import type { ResolvedSurface } from '@atlaskit/editor-ui-control-model/surface-renderer/types';
9
8
  import type { ActiveDropTargetNode, BlockControlsMeta, BlockControlsPlugin, MultiSelectDnD, NodeDecorationFactory, PluginState } from '../blockControlsPluginType';
10
9
  import { AnchorRectCache } from './utils/anchor-utils';
11
10
  export declare const key: PluginKey<PluginState>;
12
11
  export interface FlagType {
13
- /**
14
- * Whether the legacy widget-decoration drag handle is rendered. The registry surface renders
15
- * its replacement when this is false.
16
- */
17
- legacyDragHandleEnabled: boolean;
18
- surfaceNodePositionsEnabled: boolean;
19
12
  toolbarFlagsEnabled: boolean;
20
13
  }
21
14
  export declare const getDecorations: (state: EditorState) => DecorationSet | undefined;
22
- export declare const apply: (api: ExtractInjectionAPI<BlockControlsPlugin> | undefined, formatMessage: IntlShape['formatMessage'], tr: ReadonlyTransaction, currentState: PluginState, newState: EditorState, flags: FlagType, nodeViewPortalProviderAPI: PortalProviderAPI, nodeDecorationRegistry: NodeDecorationFactory[], rightSideControlsEnabled?: boolean, quickInsertButtonEnabled?: boolean, anchorRectCache?: AnchorRectCache, resizeObserverWidth?: ResizeObserver, pragmaticCleanup?: (() => void) | null, resolvedSurfaces?: readonly ResolvedSurface[], limitedModeTeardown?: {
15
+ export declare const apply: (api: ExtractInjectionAPI<BlockControlsPlugin> | undefined, formatMessage: IntlShape['formatMessage'], tr: ReadonlyTransaction, currentState: PluginState, newState: EditorState, flags: FlagType, nodeViewPortalProviderAPI: PortalProviderAPI, nodeDecorationRegistry: NodeDecorationFactory[], rightSideControlsEnabled?: boolean, quickInsertButtonEnabled?: boolean, anchorRectCache?: AnchorRectCache, resizeObserverWidth?: ResizeObserver, pragmaticCleanup?: (() => void) | null, limitedModeTeardown?: {
23
16
  done: boolean;
24
17
  }) => PluginState | {
25
18
  activeDropTargetNode: ActiveDropTargetNode | undefined;
@@ -46,7 +39,7 @@ export declare const apply: (api: ExtractInjectionAPI<BlockControlsPlugin> | und
46
39
  multiSelectDnD: MultiSelectDnD | undefined;
47
40
  surfaceNodePositions: number[];
48
41
  };
49
- export declare const createPlugin: (api: ExtractInjectionAPI<BlockControlsPlugin> | undefined, getIntl: () => IntlShape, nodeViewPortalProviderAPI: PortalProviderAPI, nodeDecorationRegistry: NodeDecorationFactory[], rightSideControlsEnabled?: boolean, quickInsertButtonEnabled?: boolean, legacyDragHandleEnabled?: boolean) => SafePlugin<PluginState | {
42
+ export declare const createPlugin: (api: ExtractInjectionAPI<BlockControlsPlugin> | undefined, getIntl: () => IntlShape, nodeViewPortalProviderAPI: PortalProviderAPI, nodeDecorationRegistry: NodeDecorationFactory[], rightSideControlsEnabled?: boolean, quickInsertButtonEnabled?: boolean) => SafePlugin<PluginState | {
50
43
  activeDropTargetNode: ActiveDropTargetNode | undefined;
51
44
  activeNode: any;
52
45
  blockMenuOptions: {
@@ -0,0 +1,8 @@
1
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
4
+ import type { BlockControlsPlugin } from '../blockControlsPluginType';
5
+ import { type SparseSurfacesState } from './utils/sparse-surfaces-state';
6
+ export declare const sparseSurfacesKey: PluginKey<SparseSurfacesState>;
7
+ /** Owns sparse anchors independently of drag/drop decorations and their lifecycle. */
8
+ export declare const createSparseSurfacesPlugin: (api: ExtractInjectionAPI<BlockControlsPlugin> | undefined) => SafePlugin<SparseSurfacesState>;
@@ -0,0 +1,89 @@
1
+ import type { EditorState, ReadonlyTransaction, Transaction } from '@atlaskit/editor-prosemirror/state';
2
+ import type { ResolvedSurface } from '@atlaskit/editor-ui-control-model/surface-renderer/types';
3
+ import type { ActiveNode } from '../../blockControlsPluginType';
4
+ export type SparseCandidateRange = {
5
+ from: number;
6
+ to: number;
7
+ };
8
+ export type SparseCandidateInvalidation = {
9
+ all?: boolean;
10
+ ids?: readonly string[];
11
+ positions?: readonly number[];
12
+ ranges?: readonly SparseCandidateRange[];
13
+ };
14
+ /**
15
+ * Viewport positions are post-transaction positions supplied by the DOM observer. The reducer
16
+ * never needs to inspect DOM or search document IDs for viewport discovery.
17
+ */
18
+ export type SparseCandidateMeta = {
19
+ /** Menu/root targets may carry context distinct from global hover activeNode; map changes invalidate positions. */
20
+ activeNodesByPosition?: ReadonlyMap<number, ActiveNode>;
21
+ changedRange?: SparseCandidateRange;
22
+ /** Set by view reconciliation when mapping and predicate evaluation are split. */
23
+ documentChanged?: boolean;
24
+ /** Registry changes must use `invalidation: { all: true }`. */
25
+ invalidation?: SparseCandidateInvalidation;
26
+ /** Complete current set; pass [] when menu/hover protection ends. */
27
+ protectedPositions?: readonly number[];
28
+ /** Property presence is significant: `visiblePositions: []` clears visible candidates. */
29
+ visiblePositions?: readonly number[];
30
+ };
31
+ export type SparseSurfaceCandidate = {
32
+ contextRevision: string;
33
+ /** Optional stable node id, used only when matching cached invalidations. */
34
+ id?: string;
35
+ /** Persistent controls keep their candidate and DOM anchor outside the viewport. */
36
+ isPersistent: boolean;
37
+ /** PM structural sharing lets reconcile detect changed cached nodes cheaply. */
38
+ nodeRef: object;
39
+ nodeSize: number;
40
+ nodeType: string;
41
+ pos: number;
42
+ /** False entries stay cached, so hidden nodes are not re-preflighted on re-entry. */
43
+ renders: boolean;
44
+ };
45
+ export type SparseSurfaceCandidateState = {
46
+ activeRevision: string;
47
+ candidates: ReadonlyMap<number, SparseSurfaceCandidate>;
48
+ positions: readonly number[];
49
+ protectedPositions: readonly number[];
50
+ visiblePositions: readonly number[];
51
+ };
52
+ export type SparseSurfaceCandidateInput = {
53
+ activeNode?: ActiveNode | null;
54
+ meta?: SparseCandidateMeta;
55
+ newState: EditorState;
56
+ previousState: SparseSurfaceCandidateState;
57
+ resolvedSurfaces: readonly ResolvedSurface[];
58
+ tr: Transaction;
59
+ };
60
+ export declare const emptySparseSurfaceCandidateState: SparseSurfaceCandidateState;
61
+ export type MapSparseSurfaceCandidatesInput = {
62
+ newState: EditorState;
63
+ previousState: SparseSurfaceCandidateState;
64
+ tr: Transaction | ReadonlyTransaction;
65
+ };
66
+ /** Map cache state during PM apply. This phase never calls isHidden or scans doc. */
67
+ export declare const mapSparseSurfaceCandidates: ({ newState, previousState, tr, }: MapSparseSurfaceCandidatesInput) => SparseSurfaceCandidateState;
68
+ export type ReconcileSparseSurfaceCandidatesInput = {
69
+ activeNode?: ActiveNode | null;
70
+ activeNodesByPosition?: ReadonlyMap<number, ActiveNode>;
71
+ changedRange?: SparseCandidateRange;
72
+ documentChanged?: boolean;
73
+ invalidation?: SparseCandidateInvalidation;
74
+ newState: EditorState;
75
+ protectedPositions?: readonly number[];
76
+ resolvedSurfaces: readonly ResolvedSurface[];
77
+ state: SparseSurfaceCandidateState;
78
+ visiblePositions?: readonly number[];
79
+ };
80
+ /**
81
+ * Reconcile after view state is current. Predicate work stays bounded to cache,
82
+ * exact visible positions, explicit ranges, and protected active/menu positions.
83
+ */
84
+ export declare const reconcileSparseSurfaceCandidates: ({ activeNodesByPosition, activeNode, changedRange, documentChanged, invalidation, newState, protectedPositions, resolvedSurfaces, state, visiblePositions, }: ReconcileSparseSurfaceCandidatesInput) => SparseSurfaceCandidateState;
85
+ /**
86
+ * Update sparse candidates. Viewport and invalidation metadata are the only
87
+ * discovery inputs; active changes re-evaluate retained cache, never document.
88
+ */
89
+ export declare const reduceSparseSurfaceCandidates: ({ activeNode, meta, newState, previousState, resolvedSurfaces, tr, }: SparseSurfaceCandidateInput) => SparseSurfaceCandidateState;
@@ -0,0 +1,20 @@
1
+ import type { BlockControlsSurfaceInvalidation } from '@atlaskit/editor-common/block-controls/surface-candidate-invalidation';
2
+ import type { EditorState, ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
3
+ import type { SparseSurfacesState } from './sparse-surfaces-state';
4
+ export type PendingSparseSurfacesState = Pick<SparseSurfacesState, 'invalidation'>;
5
+ export declare const reducePendingState: ({ invalidation, previous, tr, }: {
6
+ invalidation: BlockControlsSurfaceInvalidation | undefined;
7
+ previous: SparseSurfacesState;
8
+ tr: ReadonlyTransaction;
9
+ }) => PendingSparseSurfacesState;
10
+ export declare const isUnchangedTransaction: ({ pending, previous, tr, }: {
11
+ pending: PendingSparseSurfacesState;
12
+ previous: SparseSurfacesState;
13
+ tr: ReadonlyTransaction;
14
+ }) => boolean;
15
+ export declare const mapTransactionState: ({ newState, pending, previous, tr, }: {
16
+ newState: EditorState;
17
+ pending: PendingSparseSurfacesState;
18
+ previous: SparseSurfacesState;
19
+ tr: ReadonlyTransaction;
20
+ }) => SparseSurfacesState;