@atlaskit/editor-plugin-block-controls 8.7.2 → 8.8.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 (55) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/cjs/blockControlsPlugin.js +14 -3
  3. package/dist/cjs/pm-plugins/decorations-drag-handle.js +3 -0
  4. package/dist/cjs/pm-plugins/decorations-quick-insert-button.js +3 -0
  5. package/dist/cjs/pm-plugins/handle-mouse-over.js +27 -11
  6. package/dist/cjs/pm-plugins/interaction-tracking/commands.js +12 -1
  7. package/dist/cjs/pm-plugins/interaction-tracking/handle-mouse-move.js +96 -1
  8. package/dist/cjs/pm-plugins/interaction-tracking/pm-plugin.js +92 -3
  9. package/dist/cjs/pm-plugins/main.js +129 -25
  10. package/dist/cjs/pm-plugins/vanilla-quick-insert.js +36 -13
  11. package/dist/cjs/ui/drag-handle.js +19 -9
  12. package/dist/cjs/ui/global-styles.js +9 -4
  13. package/dist/cjs/ui/quick-insert-button.js +16 -3
  14. package/dist/cjs/ui/visibility-container.js +70 -9
  15. package/dist/es2019/blockControlsPlugin.js +12 -3
  16. package/dist/es2019/pm-plugins/decorations-drag-handle.js +3 -0
  17. package/dist/es2019/pm-plugins/decorations-quick-insert-button.js +3 -0
  18. package/dist/es2019/pm-plugins/handle-mouse-over.js +27 -11
  19. package/dist/es2019/pm-plugins/interaction-tracking/commands.js +11 -0
  20. package/dist/es2019/pm-plugins/interaction-tracking/handle-mouse-move.js +98 -3
  21. package/dist/es2019/pm-plugins/interaction-tracking/pm-plugin.js +89 -4
  22. package/dist/es2019/pm-plugins/main.js +73 -18
  23. package/dist/es2019/pm-plugins/vanilla-quick-insert.js +27 -3
  24. package/dist/es2019/ui/drag-handle.js +19 -9
  25. package/dist/es2019/ui/global-styles.js +9 -3
  26. package/dist/es2019/ui/quick-insert-button.js +17 -3
  27. package/dist/es2019/ui/visibility-container.js +65 -9
  28. package/dist/esm/blockControlsPlugin.js +14 -3
  29. package/dist/esm/pm-plugins/decorations-drag-handle.js +3 -0
  30. package/dist/esm/pm-plugins/decorations-quick-insert-button.js +3 -0
  31. package/dist/esm/pm-plugins/handle-mouse-over.js +27 -11
  32. package/dist/esm/pm-plugins/interaction-tracking/commands.js +11 -0
  33. package/dist/esm/pm-plugins/interaction-tracking/handle-mouse-move.js +98 -2
  34. package/dist/esm/pm-plugins/interaction-tracking/pm-plugin.js +93 -3
  35. package/dist/esm/pm-plugins/main.js +129 -25
  36. package/dist/esm/pm-plugins/vanilla-quick-insert.js +36 -13
  37. package/dist/esm/ui/drag-handle.js +19 -9
  38. package/dist/esm/ui/global-styles.js +9 -4
  39. package/dist/esm/ui/quick-insert-button.js +16 -3
  40. package/dist/esm/ui/visibility-container.js +68 -9
  41. package/dist/types/blockControlsPluginType.d.ts +25 -1
  42. package/dist/types/index.d.ts +1 -1
  43. package/dist/types/pm-plugins/interaction-tracking/commands.d.ts +2 -0
  44. package/dist/types/pm-plugins/interaction-tracking/handle-mouse-move.d.ts +2 -2
  45. package/dist/types/pm-plugins/interaction-tracking/pm-plugin.d.ts +5 -1
  46. package/dist/types/pm-plugins/main.d.ts +2 -2
  47. package/dist/types/ui/visibility-container.d.ts +2 -1
  48. package/dist/types-ts4.5/blockControlsPluginType.d.ts +27 -1
  49. package/dist/types-ts4.5/index.d.ts +1 -1
  50. package/dist/types-ts4.5/pm-plugins/interaction-tracking/commands.d.ts +2 -0
  51. package/dist/types-ts4.5/pm-plugins/interaction-tracking/handle-mouse-move.d.ts +2 -2
  52. package/dist/types-ts4.5/pm-plugins/interaction-tracking/pm-plugin.d.ts +5 -1
  53. package/dist/types-ts4.5/pm-plugins/main.d.ts +2 -2
  54. package/dist/types-ts4.5/ui/visibility-container.d.ts +2 -1
  55. package/package.json +5 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 8.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`884dc5b015901`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/884dc5b015901) -
8
+ [ux] Update hover logic for edit mode in edit/live pages
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies
13
+
3
14
  ## 8.7.2
4
15
 
5
16
  ### Patch Changes
@@ -11,6 +11,7 @@ var _selection = require("@atlaskit/editor-common/selection");
11
11
  var _toolbarFlagCheck = require("@atlaskit/editor-common/toolbar-flag-check");
12
12
  var _state = require("@atlaskit/editor-prosemirror/state");
13
13
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
14
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
14
15
  var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
15
16
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
16
17
  var _handleKeyDownWithPreservedSelection = require("./editor-commands/handle-key-down-with-preserved-selection");
@@ -30,8 +31,11 @@ var _globalStyles = require("./ui/global-styles");
30
31
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
31
32
  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) { (0, _defineProperty2.default)(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; }
32
33
  var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPlugin(_ref) {
33
- var api = _ref.api;
34
+ var _config$rightSideCont;
35
+ var api = _ref.api,
36
+ config = _ref.config;
34
37
  var nodeDecorationRegistry = [];
38
+ var rightSideControlsEnabled = (_config$rightSideCont = config === null || config === void 0 ? void 0 : config.rightSideControlsEnabled) !== null && _config$rightSideCont !== void 0 ? _config$rightSideCont : false;
35
39
  return {
36
40
  name: 'blockControls',
37
41
  actions: {
@@ -53,13 +57,15 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
53
57
  plugin: function plugin(_ref2) {
54
58
  var getIntl = _ref2.getIntl,
55
59
  nodeViewPortalProviderAPI = _ref2.nodeViewPortalProviderAPI;
56
- return (0, _main.createPlugin)(api, getIntl, nodeViewPortalProviderAPI, nodeDecorationRegistry);
60
+ return (0, _main.createPlugin)(api, getIntl, nodeViewPortalProviderAPI, nodeDecorationRegistry, rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true));
57
61
  }
58
62
  }];
59
63
  if ((0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) {
60
64
  pmPlugins.push({
61
65
  name: 'blockControlsInteractionTrackingPlugin',
62
- plugin: _pmPlugin.createInteractionTrackingPlugin
66
+ plugin: function plugin() {
67
+ return (0, _pmPlugin.createInteractionTrackingPlugin)(rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true));
68
+ }
63
69
  });
64
70
  }
65
71
  if ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true)) {
@@ -332,6 +338,11 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
332
338
  if ((0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) {
333
339
  var _interactionTrackingP2, _interactionTrackingP3;
334
340
  sharedState.isMouseOut = (_interactionTrackingP2 = (_interactionTrackingP3 = _pmPlugin.interactionTrackingPluginKey.getState(editorState)) === null || _interactionTrackingP3 === void 0 ? void 0 : _interactionTrackingP3.isMouseOut) !== null && _interactionTrackingP2 !== void 0 ? _interactionTrackingP2 : false;
341
+ sharedState.rightSideControlsEnabled = rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true);
342
+ if (rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true)) {
343
+ var _interactionTrackingP4;
344
+ sharedState.hoverSide = (_interactionTrackingP4 = _pmPlugin.interactionTrackingPluginKey.getState(editorState)) === null || _interactionTrackingP4 === void 0 ? void 0 : _interactionTrackingP4.hoverSide;
345
+ }
335
346
  }
336
347
  if ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true)) {
337
348
  var _selectionPreservatio;
@@ -85,6 +85,9 @@ var dragHandleDecoration = exports.dragHandleDecoration = function dragHandleDec
85
85
  var element = document.createElement('span');
86
86
  // inline decoration causes focus issues when refocusing Editor into first line
87
87
  element.style.display = 'block';
88
+ if ((0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true)) {
89
+ element.setAttribute('data-blocks-decorator-widget', 'true');
90
+ }
88
91
  element.setAttribute('data-testid', 'block-ctrl-decorator-widget');
89
92
  element.setAttribute('data-blocks-drag-handle-container', 'true');
90
93
  element.setAttribute('data-blocks-drag-handle-key', key);
@@ -76,6 +76,9 @@ var quickInsertButtonDecoration = exports.quickInsertButtonDecoration = function
76
76
  }
77
77
  element.contentEditable = 'false';
78
78
  element.setAttribute('data-blocks-quick-insert-container', 'true');
79
+ if ((0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true)) {
80
+ element.setAttribute('data-blocks-quick-insert-button', 'true');
81
+ }
79
82
  element.setAttribute('data-testid', 'block-ctrl-quick-insert-button');
80
83
  if ((0, _experiments.editorExperiment)('platform_editor_block_control_optimise_render', true, {
81
84
  exposure: true
@@ -45,7 +45,7 @@ var getDefaultNodeSelector = (0, _memoizeOne.default)(function () {
45
45
  return getNodeSelector([].concat((0, _toConsumableArray2.default)(_decorationsAnchor.IGNORE_NODES_NEXT), ['media']), [].concat((0, _toConsumableArray2.default)(_decorationsAnchor.IGNORE_NODE_DESCENDANTS_ADVANCED_LAYOUT), ['table']));
46
46
  });
47
47
  var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, event, api) {
48
- var _api$blockControls, _api$editorDisabled, _target$classList;
48
+ var _api$blockControls, _api$editorDisabled, _api$editorViewMode, _api$blockControls$sh, _api$blockControls2, _target$classList;
49
49
  var _ref = (api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
50
50
  isDragging = _ref.isDragging,
51
51
  activeNode = _ref.activeNode,
@@ -56,10 +56,14 @@ var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, e
56
56
  editorDisabled: false
57
57
  },
58
58
  editorDisabled = _ref2.editorDisabled;
59
+ var editorViewMode = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode;
60
+ var isViewMode = editorViewMode === 'view';
59
61
  var toolbarFlagsEnabled = (0, _toolbarFlagCheck.areToolbarFlagsEnabled)(Boolean(api === null || api === void 0 ? void 0 : api.toolbar));
60
62
 
61
- // We shouldn't be firing mouse over transactions when the editor is disabled
62
- if (editorDisabled) {
63
+ // We shouldn't be firing mouse over transactions when the editor is disabled,
64
+ // except in view mode when right-side controls are enabled (show controls on block hover)
65
+ var rightSideControlsEnabled = (_api$blockControls$sh = api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || (_api$blockControls2 = _api$blockControls2.sharedState.currentState()) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.rightSideControlsEnabled) !== null && _api$blockControls$sh !== void 0 ? _api$blockControls$sh : false;
66
+ if (editorDisabled && (!isViewMode || !(rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true)))) {
63
67
  return false;
64
68
  }
65
69
 
@@ -82,6 +86,18 @@ var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, e
82
86
  return false;
83
87
  }
84
88
  var rootElement = target === null || target === void 0 ? void 0 : target.closest(isNativeAnchorSupported ? getDefaultNodeSelector() : "[data-drag-handler-anchor-name]");
89
+
90
+ // When hovering over the right-edge button (rendered in a portal outside the block), resolve the
91
+ // block from the container's anchor so activeNode stays set and the button remains visible.
92
+ if (!rootElement && rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true)) {
93
+ var rightEdgeContainer = target === null || target === void 0 ? void 0 : target.closest('[data-blocks-right-edge-button-container]');
94
+ if (rightEdgeContainer) {
95
+ var anchor = rightEdgeContainer.getAttribute('data-blocks-right-edge-button-anchor');
96
+ if (anchor) {
97
+ rootElement = view.dom.querySelector("[".concat((0, _domAttrName.getAnchorAttrName)(), "=\"").concat(CSS.escape(anchor), "\"]"));
98
+ }
99
+ }
100
+ }
85
101
  if (rootElement) {
86
102
  var _rootElement$parentEl;
87
103
  // We want to exlude handles from showing for empty paragraph and heading nodes
@@ -190,22 +206,22 @@ var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, e
190
206
  // as when it is a multi-selection, the showDragHandleAt command interfere with selection
191
207
  // sometimes makes the multi-selection not continous after block menu is opened with keyboard
192
208
  if (!(isMultipleSelected && isMenuOpen && blockMenuOptions !== null && blockMenuOptions !== void 0 && blockMenuOptions.openedViaKeyboard)) {
193
- var _api$core, _api$blockControls2;
194
- api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.showDragHandleAt(targetPos, anchorName, nodeType, undefined, rootPos !== null && rootPos !== void 0 ? rootPos : targetPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType));
209
+ var _api$core, _api$blockControls3;
210
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands.showDragHandleAt(targetPos, anchorName, nodeType, undefined, rootPos !== null && rootPos !== void 0 ? rootPos : targetPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType));
195
211
  }
196
212
  } else {
197
- var _api$core2, _api$blockControls3;
198
- api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands.showDragHandleAt(targetPos, anchorName, nodeType, undefined, rootPos !== null && rootPos !== void 0 ? rootPos : targetPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType));
213
+ var _api$core2, _api$blockControls4;
214
+ api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 ? void 0 : _api$blockControls4.commands.showDragHandleAt(targetPos, anchorName, nodeType, undefined, rootPos !== null && rootPos !== void 0 ? rootPos : targetPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType));
199
215
  }
200
216
  } else {
201
- var _api$core3, _api$blockControls4;
202
- api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 ? void 0 : _api$blockControls4.commands.showDragHandleAt(targetPos, anchorName, nodeType));
217
+ var _api$core3, _api$blockControls5;
218
+ api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(api === null || api === void 0 || (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 ? void 0 : _api$blockControls5.commands.showDragHandleAt(targetPos, anchorName, nodeType));
203
219
  }
204
220
  if ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true)) {
205
221
  var _api$userIntent;
206
222
  if (isMenuOpen && originalAnchorName && (api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 || (_api$userIntent = _api$userIntent.sharedState.currentState()) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.currentUserIntent) === 'blockMenuOpen') {
207
- var _api$core4, _api$blockControls5;
208
- api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(api === null || api === void 0 || (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 ? void 0 : _api$blockControls5.commands.toggleBlockMenu());
223
+ var _api$core4, _api$blockControls6;
224
+ api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(api === null || api === void 0 || (_api$blockControls6 = api.blockControls) === null || _api$blockControls6 === void 0 ? void 0 : _api$blockControls6.commands.toggleBlockMenu());
209
225
  }
210
226
  }
211
227
  }
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.stopEditing = exports.startEditing = exports.mouseLeave = exports.mouseEnter = void 0;
6
+ exports.stopEditing = exports.startEditing = exports.setHoverSide = exports.mouseLeave = exports.mouseEnter = exports.clearHoverSide = void 0;
7
7
  var _pmPlugin = require("./pm-plugin");
8
8
  var stopEditing = exports.stopEditing = function stopEditing(view) {
9
9
  view.dispatch(view.state.tr.setMeta(_pmPlugin.interactionTrackingPluginKey, {
@@ -24,4 +24,15 @@ var mouseEnter = exports.mouseEnter = function mouseEnter(view) {
24
24
  view.dispatch(view.state.tr.setMeta(_pmPlugin.interactionTrackingPluginKey, {
25
25
  type: 'mouseEnter'
26
26
  }));
27
+ };
28
+ var setHoverSide = exports.setHoverSide = function setHoverSide(view, side) {
29
+ view.dispatch(view.state.tr.setMeta(_pmPlugin.interactionTrackingPluginKey, {
30
+ type: 'setHoverSide',
31
+ side: side
32
+ }));
33
+ };
34
+ var clearHoverSide = exports.clearHoverSide = function clearHoverSide(view) {
35
+ view.dispatch(view.state.tr.setMeta(_pmPlugin.interactionTrackingPluginKey, {
36
+ type: 'clearHoverSide'
37
+ }));
27
38
  };
@@ -4,17 +4,112 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.handleMouseMove = exports.handleMouseLeave = exports.handleMouseEnter = void 0;
7
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
7
8
  var _commands = require("./commands");
8
9
  var _pmPlugin = require("./pm-plugin");
9
- var handleMouseMove = exports.handleMouseMove = function handleMouseMove(view) {
10
+ /** Per-view pending hover state; avoids cross-editor singleton. */
11
+ var pendingByView = new WeakMap();
12
+
13
+ /** Per-view RAF handle so clearPendingHoverSide cancels only that view's callback. */
14
+ var rafIdByView = new WeakMap();
15
+ var cancelScheduledProcessForView = function cancelScheduledProcessForView(view) {
16
+ var id = rafIdByView.get(view);
17
+ if (id !== undefined) {
18
+ cancelAnimationFrame(id);
19
+ rafIdByView.delete(view);
20
+ }
21
+ };
22
+ var clearPendingHoverSide = function clearPendingHoverSide(view) {
23
+ pendingByView.delete(view);
24
+ cancelScheduledProcessForView(view);
25
+ };
26
+ var BLOCK_SELECTORS = '[data-node-anchor], [data-drag-handler-anchor-name]';
27
+ var TABLE_SELECTOR = '[data-prosemirror-node-name="table"]';
28
+ var RIGHT_EDGE_SELECTOR = '[data-blocks-right-edge-button-container]';
29
+ var isInsideTable = function isInsideTable(element) {
30
+ var _element$getAttribute;
31
+ return element.closest(TABLE_SELECTOR) !== null || ((_element$getAttribute = element.getAttribute) === null || _element$getAttribute === void 0 ? void 0 : _element$getAttribute.call(element, 'data-prosemirror-node-name')) === 'table';
32
+ };
33
+ var processHoverSide = function processHoverSide(view) {
34
+ var event = pendingByView.get(view);
35
+ if (!event) {
36
+ return;
37
+ }
38
+ pendingByView.delete(view);
39
+ rafIdByView.delete(view);
40
+ var editorContentArea = view.dom.closest('.ak-editor-content-area');
41
+ if (!(editorContentArea instanceof HTMLElement)) {
42
+ return;
43
+ }
44
+ var state = (0, _pmPlugin.getInteractionTrackingState)(view.state);
45
+ var target = event.target instanceof HTMLElement ? event.target : null;
46
+
47
+ // When hovering over block controls directly, infer side from which control we're over.
48
+ // This is more reliable than bounds when controls are in portals outside the editor DOM.
49
+ var rightEdgeElement = target === null || target === void 0 ? void 0 : target.closest(RIGHT_EDGE_SELECTOR);
50
+ if (rightEdgeElement) {
51
+ if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'right') {
52
+ (0, _commands.setHoverSide)(view, 'right');
53
+ }
54
+ return;
55
+ }
56
+ var leftControlElement = target === null || target === void 0 ? void 0 : target.closest('[data-blocks-drag-handle-container], [data-testid="block-ctrl-drag-handle"], [data-testid="block-ctrl-drag-handle-container"], [data-testid="block-ctrl-decorator-widget"], [data-testid="block-ctrl-quick-insert-button"]');
57
+ if (leftControlElement) {
58
+ if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'left') {
59
+ (0, _commands.setHoverSide)(view, 'left');
60
+ }
61
+ return;
62
+ }
63
+
64
+ // Use the hovered block's midpoint when hovering over block content.
65
+ var blockElement = target === null || target === void 0 ? void 0 : target.closest(BLOCK_SELECTORS);
66
+ var boundsElement = blockElement instanceof HTMLElement ? blockElement : editorContentArea;
67
+
68
+ // Tables show block controls at table level; don't restrict by side so drag handle
69
+ // stays visible when hovering anywhere in the table (e.g. paragraph in second cell).
70
+ if (isInsideTable(boundsElement)) {
71
+ if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== undefined) {
72
+ (0, _commands.clearHoverSide)(view);
73
+ }
74
+ return;
75
+ }
76
+ var _boundsElement$getBou = boundsElement.getBoundingClientRect(),
77
+ left = _boundsElement$getBou.left,
78
+ right = _boundsElement$getBou.right;
79
+ var midpoint = (left + right) / 2;
80
+ var nextHoverSide = event.clientX > midpoint ? 'right' : 'left';
81
+ if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== nextHoverSide) {
82
+ (0, _commands.setHoverSide)(view, nextHoverSide);
83
+ }
84
+ };
85
+ var handleMouseMove = exports.handleMouseMove = function handleMouseMove(view, event) {
86
+ var rightSideControlsEnabled = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
10
87
  var state = (0, _pmPlugin.getInteractionTrackingState)(view.state);
11
88
  // if user has stopped editing and moved their mouse, show block controls again
12
89
  if (state !== null && state !== void 0 && state.isEditing) {
13
90
  (0, _commands.stopEditing)(view);
14
91
  }
92
+
93
+ // Only track hover side when right-side controls are enabled and experiment is on (performance)
94
+ if (!rightSideControlsEnabled || !(0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true)) {
95
+ return false;
96
+ }
97
+ if (!(event instanceof MouseEvent)) {
98
+ return false;
99
+ }
100
+ pendingByView.set(view, event);
101
+ cancelScheduledProcessForView(view);
102
+ var id = requestAnimationFrame(function () {
103
+ processHoverSide(view);
104
+ });
105
+ rafIdByView.set(view, id);
15
106
  return false;
16
107
  };
17
108
  var handleMouseLeave = exports.handleMouseLeave = function handleMouseLeave(view) {
109
+ var rightSideControlsEnabled = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
110
+ if (rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true)) {
111
+ clearPendingHoverSide(view);
112
+ }
18
113
  (0, _commands.mouseLeave)(view);
19
114
  return false;
20
115
  };
@@ -9,13 +9,21 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
9
9
  var _bindEventListener = require("bind-event-listener");
10
10
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
11
11
  var _state = require("@atlaskit/editor-prosemirror/state");
12
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
12
13
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
13
14
  var _handleKeyDown = require("./handle-key-down");
14
15
  var _handleMouseMove = require("./handle-mouse-move");
15
16
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
16
17
  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) { (0, _defineProperty2.default)(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; }
18
+ /** Elements that extend the editor hover area (block controls, right-edge button, etc.) */
19
+ var BLOCK_CONTROLS_HOVER_AREA_SELECTOR = '[data-blocks-right-edge-button-container], [data-blocks-drag-handle-container], [data-testid="block-ctrl-drag-handle"], [data-testid="block-ctrl-drag-handle-container"], [data-testid="block-ctrl-decorator-widget"], [data-testid="block-ctrl-quick-insert-button"]';
20
+ var MOUSE_LEAVE_DEBOUNCE_MS = 200;
21
+ var isMovingToBlockControlsArea = function isMovingToBlockControlsArea(target) {
22
+ return target instanceof Element && !!target.closest(BLOCK_CONTROLS_HOVER_AREA_SELECTOR);
23
+ };
17
24
  var interactionTrackingPluginKey = exports.interactionTrackingPluginKey = new _state.PluginKey('interactionTrackingPlugin');
18
25
  var createInteractionTrackingPlugin = exports.createInteractionTrackingPlugin = function createInteractionTrackingPlugin() {
26
+ var rightSideControlsEnabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
19
27
  return new _safePlugin.SafePlugin({
20
28
  key: interactionTrackingPluginKey,
21
29
  state: {
@@ -40,10 +48,17 @@ var createInteractionTrackingPlugin = exports.createInteractionTrackingPlugin =
40
48
  break;
41
49
  case 'mouseLeave':
42
50
  newState.isMouseOut = true;
51
+ newState.hoverSide = undefined;
43
52
  break;
44
53
  case 'mouseEnter':
45
54
  newState.isMouseOut = false;
46
55
  break;
56
+ case 'setHoverSide':
57
+ newState.hoverSide = meta.side;
58
+ break;
59
+ case 'clearHoverSide':
60
+ newState.hoverSide = undefined;
61
+ break;
47
62
  }
48
63
  return _objectSpread(_objectSpread({}, pluginState), newState);
49
64
  }
@@ -51,30 +66,104 @@ var createInteractionTrackingPlugin = exports.createInteractionTrackingPlugin =
51
66
  props: {
52
67
  handleKeyDown: _handleKeyDown.handleKeyDown,
53
68
  handleDOMEvents: {
54
- mousemove: _handleMouseMove.handleMouseMove
69
+ mousemove: function mousemove(view, event) {
70
+ return (0, _handleMouseMove.handleMouseMove)(view, event, rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true));
71
+ }
55
72
  }
56
73
  },
57
74
  view: (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1') ? function (view) {
58
75
  var editorContentArea = view.dom.closest('.ak-editor-content-area');
76
+ var remixRightSideEnabled = rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true);
59
77
  var unbindMouseEnter;
60
78
  var unbindMouseLeave;
79
+ var unbindDocumentMouseMove;
80
+ var mouseLeaveTimeoutId = null;
81
+ var lastMousePosition = {
82
+ x: 0,
83
+ y: 0
84
+ };
85
+ var scheduleMouseLeave = function scheduleMouseLeave(event) {
86
+ if (mouseLeaveTimeoutId) {
87
+ clearTimeout(mouseLeaveTimeoutId);
88
+ mouseLeaveTimeoutId = null;
89
+ }
90
+
91
+ // Don't set isMouseOut when moving to block controls (right-edge button, drag handle, etc.)
92
+ if (rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true) && isMovingToBlockControlsArea(event.relatedTarget)) {
93
+ return;
94
+ }
95
+ mouseLeaveTimeoutId = setTimeout(function () {
96
+ mouseLeaveTimeoutId = null;
97
+ // Before dispatching, check if mouse has moved to block controls (e.g. through empty space)
98
+ if (rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true) && typeof document !== 'undefined') {
99
+ var el = document.elementFromPoint(lastMousePosition.x, lastMousePosition.y);
100
+ if (el && isMovingToBlockControlsArea(el)) {
101
+ return;
102
+ }
103
+ }
104
+ (0, _handleMouseMove.handleMouseLeave)(view, rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true));
105
+ }, MOUSE_LEAVE_DEBOUNCE_MS);
106
+ };
107
+ var cancelScheduledMouseLeave = function cancelScheduledMouseLeave() {
108
+ if (mouseLeaveTimeoutId) {
109
+ clearTimeout(mouseLeaveTimeoutId);
110
+ mouseLeaveTimeoutId = null;
111
+ }
112
+ };
61
113
  if (editorContentArea) {
114
+ if (remixRightSideEnabled && typeof document !== 'undefined') {
115
+ unbindDocumentMouseMove = (0, _bindEventListener.bind)(document, {
116
+ type: 'mousemove',
117
+ listener: function listener(event) {
118
+ lastMousePosition = {
119
+ x: event.clientX,
120
+ y: event.clientY
121
+ };
122
+ // Use document-level mousemove so we get events when hovering over block
123
+ // controls (which may be in portals outside the editor DOM). Without this,
124
+ // handleDOMEvents.mousemove only fires when over the editor content.
125
+ if (editorContentArea.contains(event.target) || isMovingToBlockControlsArea(event.target)) {
126
+ (0, _handleMouseMove.handleMouseMove)(view, event, rightSideControlsEnabled && (0, _expValEquals.expValEquals)('confluence_remix_icon_right_side', 'isEnabled', true));
127
+ }
128
+ },
129
+ options: {
130
+ passive: true
131
+ }
132
+ });
133
+ }
62
134
  unbindMouseEnter = (0, _bindEventListener.bind)(editorContentArea, {
63
135
  type: 'mouseenter',
64
136
  listener: function listener() {
137
+ if (remixRightSideEnabled) {
138
+ cancelScheduledMouseLeave();
139
+ }
65
140
  (0, _handleMouseMove.handleMouseEnter)(view);
66
141
  }
67
142
  });
68
143
  unbindMouseLeave = (0, _bindEventListener.bind)(editorContentArea, {
69
144
  type: 'mouseleave',
70
- listener: function listener() {
71
- (0, _handleMouseMove.handleMouseLeave)(view);
145
+ listener: function listener(event) {
146
+ var e = event;
147
+ lastMousePosition = {
148
+ x: e.clientX,
149
+ y: e.clientY
150
+ };
151
+ if (remixRightSideEnabled) {
152
+ scheduleMouseLeave(e);
153
+ } else {
154
+ (0, _handleMouseMove.handleMouseLeave)(view, false);
155
+ }
72
156
  }
73
157
  });
74
158
  }
75
159
  return {
76
160
  destroy: function destroy() {
77
161
  var _unbindMouseEnter, _unbindMouseLeave;
162
+ if (remixRightSideEnabled) {
163
+ var _unbindDocumentMouseM;
164
+ cancelScheduledMouseLeave();
165
+ (_unbindDocumentMouseM = unbindDocumentMouseMove) === null || _unbindDocumentMouseM === void 0 || _unbindDocumentMouseM();
166
+ }
78
167
  (_unbindMouseEnter = unbindMouseEnter) === null || _unbindMouseEnter === void 0 || _unbindMouseEnter();
79
168
  (_unbindMouseLeave = unbindMouseLeave) === null || _unbindMouseLeave === void 0 || _unbindMouseLeave();
80
169
  }